diff options
Diffstat (limited to 'src/test/ui/asm')
104 files changed, 8004 insertions, 0 deletions
diff --git a/src/test/ui/asm/aarch64/bad-options.rs b/src/test/ui/asm/aarch64/bad-options.rs new file mode 100644 index 000000000..6172027a2 --- /dev/null +++ b/src/test/ui/asm/aarch64/bad-options.rs @@ -0,0 +1,39 @@ +// only-aarch64 + +use std::arch::{asm, global_asm}; + +fn main() { + let mut foo = 0; + unsafe { + asm!("", options(nomem, readonly)); + //~^ ERROR the `nomem` and `readonly` options are mutually exclusive + asm!("", options(pure, nomem, noreturn)); + //~^ ERROR the `pure` and `noreturn` options are mutually exclusive + //~^^ ERROR asm with the `pure` option must have at least one output + asm!("{}", in(reg) foo, options(pure, nomem)); + //~^ ERROR asm with the `pure` option must have at least one output + asm!("{}", out(reg) foo, options(noreturn)); + //~^ ERROR asm outputs are not allowed with the `noreturn` option + } + + unsafe { + asm!("", clobber_abi("foo")); + //~^ ERROR invalid ABI for `clobber_abi` + asm!("{}", out(reg) foo, clobber_abi("C")); + //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs + asm!("", out("x0") foo, clobber_abi("C")); + } +} + +global_asm!("", options(nomem)); +//~^ ERROR expected one of +global_asm!("", options(readonly)); +//~^ ERROR expected one of +global_asm!("", options(noreturn)); +//~^ ERROR expected one of +global_asm!("", options(pure)); +//~^ ERROR expected one of +global_asm!("", options(nostack)); +//~^ ERROR expected one of +global_asm!("", options(preserves_flags)); +//~^ ERROR expected one of diff --git a/src/test/ui/asm/aarch64/bad-options.stderr b/src/test/ui/asm/aarch64/bad-options.stderr new file mode 100644 index 000000000..21bcc4a9c --- /dev/null +++ b/src/test/ui/asm/aarch64/bad-options.stderr @@ -0,0 +1,84 @@ +error: the `nomem` and `readonly` options are mutually exclusive + --> $DIR/bad-options.rs:8:18 + | +LL | asm!("", options(nomem, readonly)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the `pure` and `noreturn` options are mutually exclusive + --> $DIR/bad-options.rs:10:18 + | +LL | asm!("", options(pure, nomem, noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: asm with the `pure` option must have at least one output + --> $DIR/bad-options.rs:10:18 + | +LL | asm!("", options(pure, nomem, noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: asm with the `pure` option must have at least one output + --> $DIR/bad-options.rs:13:33 + | +LL | asm!("{}", in(reg) foo, options(pure, nomem)); + | ^^^^^^^^^^^^^^^^^^^^ + +error: asm outputs are not allowed with the `noreturn` option + --> $DIR/bad-options.rs:15:20 + | +LL | asm!("{}", out(reg) foo, options(noreturn)); + | ^^^^^^^^^^^^ + +error: asm with `clobber_abi` must specify explicit registers for outputs + --> $DIR/bad-options.rs:22:20 + | +LL | asm!("{}", out(reg) foo, clobber_abi("C")); + | ^^^^^^^^^^^^ ---------------- clobber_abi + | | + | generic outputs + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/bad-options.rs:28:25 + | +LL | global_asm!("", options(nomem)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `readonly` + --> $DIR/bad-options.rs:30:25 + | +LL | global_asm!("", options(readonly)); + | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn` + --> $DIR/bad-options.rs:32:25 + | +LL | global_asm!("", options(noreturn)); + | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `pure` + --> $DIR/bad-options.rs:34:25 + | +LL | global_asm!("", options(pure)); + | ^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nostack` + --> $DIR/bad-options.rs:36:25 + | +LL | global_asm!("", options(nostack)); + | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags` + --> $DIR/bad-options.rs:38:25 + | +LL | global_asm!("", options(preserves_flags)); + | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: invalid ABI for `clobber_abi` + --> $DIR/bad-options.rs:20:18 + | +LL | asm!("", clobber_abi("foo")); + | ^^^^^^^^^^^^^^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi` + +error: aborting due to 13 previous errors + diff --git a/src/test/ui/asm/aarch64/bad-reg.rs b/src/test/ui/asm/aarch64/bad-reg.rs new file mode 100644 index 000000000..2b6a9b71c --- /dev/null +++ b/src/test/ui/asm/aarch64/bad-reg.rs @@ -0,0 +1,61 @@ +// only-aarch64 +// compile-flags: -C target-feature=+neon + +#![feature(asm_const, asm_sym)] + +use std::arch::asm; + +fn main() { + let mut foo = 0; + let mut bar = 0; + unsafe { + // Bad register/register class + + asm!("{}", in(foo) foo); + //~^ ERROR invalid register class `foo`: unknown register class + asm!("", in("foo") foo); + //~^ ERROR invalid register `foo`: unknown register + asm!("{:z}", in(reg) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:r}", in(vreg) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:r}", in(vreg_low16) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:a}", const 0); + //~^ ERROR asm template modifiers are not allowed for `const` arguments + asm!("{:a}", sym main); + //~^ ERROR asm template modifiers are not allowed for `sym` arguments + asm!("", in("x29") foo); + //~^ ERROR invalid register `x29`: the frame pointer cannot be used as an operand + asm!("", in("sp") foo); + //~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand + asm!("", in("xzr") foo); + //~^ ERROR invalid register `xzr`: the zero register cannot be used as an operand + asm!("", in("x19") foo); + //~^ ERROR invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm + + asm!("", in("p0") foo); + //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output + //~| ERROR type `i32` cannot be used with this register class + asm!("", out("p0") _); + asm!("{}", in(preg) foo); + //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output + //~| ERROR type `i32` cannot be used with this register class + asm!("{}", out(preg) _); + //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output + + // Explicit register conflicts + // (except in/lateout which don't conflict) + + asm!("", in("x0") foo, in("w0") bar); + //~^ ERROR register `x0` conflicts with register `x0` + asm!("", in("x0") foo, out("x0") bar); + //~^ ERROR register `x0` conflicts with register `x0` + asm!("", in("w0") foo, lateout("w0") bar); + asm!("", in("v0") foo, in("q0") bar); + //~^ ERROR register `v0` conflicts with register `v0` + asm!("", in("v0") foo, out("q0") bar); + //~^ ERROR register `v0` conflicts with register `v0` + asm!("", in("v0") foo, lateout("q0") bar); + } +} diff --git a/src/test/ui/asm/aarch64/bad-reg.stderr b/src/test/ui/asm/aarch64/bad-reg.stderr new file mode 100644 index 000000000..0ba627dac --- /dev/null +++ b/src/test/ui/asm/aarch64/bad-reg.stderr @@ -0,0 +1,162 @@ +error: invalid register class `foo`: unknown register class + --> $DIR/bad-reg.rs:14:20 + | +LL | asm!("{}", in(foo) foo); + | ^^^^^^^^^^^ + +error: invalid register `foo`: unknown register + --> $DIR/bad-reg.rs:16:18 + | +LL | asm!("", in("foo") foo); + | ^^^^^^^^^^^^^ + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:18:15 + | +LL | asm!("{:z}", in(reg) foo); + | ^^^^ ----------- argument + | | + | template modifier + | + = note: the `reg` register class supports the following template modifiers: `w`, `x` + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:20:15 + | +LL | asm!("{:r}", in(vreg) foo); + | ^^^^ ------------ argument + | | + | template modifier + | + = note: the `vreg` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v` + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:22:15 + | +LL | asm!("{:r}", in(vreg_low16) foo); + | ^^^^ ------------------ argument + | | + | template modifier + | + = note: the `vreg_low16` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v` + +error: asm template modifiers are not allowed for `const` arguments + --> $DIR/bad-reg.rs:24:15 + | +LL | asm!("{:a}", const 0); + | ^^^^ ------- argument + | | + | template modifier + +error: asm template modifiers are not allowed for `sym` arguments + --> $DIR/bad-reg.rs:26:15 + | +LL | asm!("{:a}", sym main); + | ^^^^ -------- argument + | | + | template modifier + +error: invalid register `x29`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:28:18 + | +LL | asm!("", in("x29") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:30:18 + | +LL | asm!("", in("sp") foo); + | ^^^^^^^^^^^^ + +error: invalid register `xzr`: the zero register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:32:18 + | +LL | asm!("", in("xzr") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:34:18 + | +LL | asm!("", in("x19") foo); + | ^^^^^^^^^^^^^ + +error: register class `preg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:37:18 + | +LL | asm!("", in("p0") foo); + | ^^^^^^^^^^^^ + +error: register class `preg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:41:20 + | +LL | asm!("{}", in(preg) foo); + | ^^^^^^^^^^^^ + +error: register class `preg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:44:20 + | +LL | asm!("{}", out(preg) _); + | ^^^^^^^^^^^ + +error: register `x0` conflicts with register `x0` + --> $DIR/bad-reg.rs:50:32 + | +LL | asm!("", in("x0") foo, in("w0") bar); + | ------------ ^^^^^^^^^^^^ register `x0` + | | + | register `x0` + +error: register `x0` conflicts with register `x0` + --> $DIR/bad-reg.rs:52:32 + | +LL | asm!("", in("x0") foo, out("x0") bar); + | ------------ ^^^^^^^^^^^^^ register `x0` + | | + | register `x0` + | +help: use `lateout` instead of `out` to avoid conflict + --> $DIR/bad-reg.rs:52:18 + | +LL | asm!("", in("x0") foo, out("x0") bar); + | ^^^^^^^^^^^^ + +error: register `v0` conflicts with register `v0` + --> $DIR/bad-reg.rs:55:32 + | +LL | asm!("", in("v0") foo, in("q0") bar); + | ------------ ^^^^^^^^^^^^ register `v0` + | | + | register `v0` + +error: register `v0` conflicts with register `v0` + --> $DIR/bad-reg.rs:57:32 + | +LL | asm!("", in("v0") foo, out("q0") bar); + | ------------ ^^^^^^^^^^^^^ register `v0` + | | + | register `v0` + | +help: use `lateout` instead of `out` to avoid conflict + --> $DIR/bad-reg.rs:57:18 + | +LL | asm!("", in("v0") foo, out("q0") bar); + | ^^^^^^^^^^^^ + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:37:27 + | +LL | asm!("", in("p0") foo); + | ^^^ + | + = note: register class `preg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:41:29 + | +LL | asm!("{}", in(preg) foo); + | ^^^ + | + = note: register class `preg` supports these types: + +error: aborting due to 20 previous errors + diff --git a/src/test/ui/asm/aarch64/const.rs b/src/test/ui/asm/aarch64/const.rs new file mode 100644 index 000000000..de299bfdb --- /dev/null +++ b/src/test/ui/asm/aarch64/const.rs @@ -0,0 +1,44 @@ +// only-aarch64 +// run-pass +// needs-asm-support +// revisions: mirunsafeck thirunsafeck +// [thirunsafeck]compile-flags: -Z thir-unsafeck + +#![feature(asm_const)] + +use std::arch::{asm, global_asm}; + +fn const_generic<const X: usize>() -> usize { + unsafe { + let a: usize; + asm!("mov {}, {}", out(reg) a, const X); + a + } +} + +const fn constfn(x: usize) -> usize { + x +} + +fn main() { + unsafe { + let a: usize; + asm!("mov {}, {}", out(reg) a, const 5); + assert_eq!(a, 5); + + let b: usize; + asm!("mov {}, {}", out(reg) b, const constfn(5)); + assert_eq!(b, 5); + + let c: usize; + asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5)); + assert_eq!(c, 10); + } + + let d = const_generic::<5>(); + assert_eq!(d, 5); +} + +global_asm!("mov x0, {}", const 5); +global_asm!("mov x0, {}", const constfn(5)); +global_asm!("mov x0, {}", const constfn(5) + constfn(5)); diff --git a/src/test/ui/asm/aarch64/duplicate-options.fixed b/src/test/ui/asm/aarch64/duplicate-options.fixed new file mode 100644 index 000000000..fa1dd4aef --- /dev/null +++ b/src/test/ui/asm/aarch64/duplicate-options.fixed @@ -0,0 +1,27 @@ +// only-aarch64 +// needs-asm-support +// run-rustfix + +use std::arch::asm; + +fn main() { + unsafe { + asm!("", options(nomem, )); + //~^ ERROR the `nomem` option was already provided + asm!("", options(preserves_flags, )); + //~^ ERROR the `preserves_flags` option was already provided + asm!("", options(nostack, preserves_flags), options()); + //~^ ERROR the `nostack` option was already provided + asm!("", options(nostack, ), options(), options()); + //~^ ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + asm!( + "", + options(nomem, noreturn), + options(preserves_flags, ), //~ ERROR the `noreturn` option was already provided + options( nostack), //~ ERROR the `nomem` option was already provided + options(), //~ ERROR the `noreturn` option was already provided + ); + } +} diff --git a/src/test/ui/asm/aarch64/duplicate-options.rs b/src/test/ui/asm/aarch64/duplicate-options.rs new file mode 100644 index 000000000..b2d3fe7d9 --- /dev/null +++ b/src/test/ui/asm/aarch64/duplicate-options.rs @@ -0,0 +1,27 @@ +// only-aarch64 +// needs-asm-support +// run-rustfix + +use std::arch::asm; + +fn main() { + unsafe { + asm!("", options(nomem, nomem)); + //~^ ERROR the `nomem` option was already provided + asm!("", options(preserves_flags, preserves_flags)); + //~^ ERROR the `preserves_flags` option was already provided + asm!("", options(nostack, preserves_flags), options(nostack)); + //~^ ERROR the `nostack` option was already provided + asm!("", options(nostack, nostack), options(nostack), options(nostack)); + //~^ ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + asm!( + "", + options(nomem, noreturn), + options(preserves_flags, noreturn), //~ ERROR the `noreturn` option was already provided + options(nomem, nostack), //~ ERROR the `nomem` option was already provided + options(noreturn), //~ ERROR the `noreturn` option was already provided + ); + } +} diff --git a/src/test/ui/asm/aarch64/duplicate-options.stderr b/src/test/ui/asm/aarch64/duplicate-options.stderr new file mode 100644 index 000000000..feb3838f4 --- /dev/null +++ b/src/test/ui/asm/aarch64/duplicate-options.stderr @@ -0,0 +1,56 @@ +error: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:9:33 + | +LL | asm!("", options(nomem, nomem)); + | ^^^^^ this option was already provided + +error: the `preserves_flags` option was already provided + --> $DIR/duplicate-options.rs:11:43 + | +LL | asm!("", options(preserves_flags, preserves_flags)); + | ^^^^^^^^^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:13:61 + | +LL | asm!("", options(nostack, preserves_flags), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:15:35 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:15:53 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:15:71 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `noreturn` option was already provided + --> $DIR/duplicate-options.rs:22:38 + | +LL | options(preserves_flags, noreturn), + | ^^^^^^^^ this option was already provided + +error: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:23:21 + | +LL | options(nomem, nostack), + | ^^^^^ this option was already provided + +error: the `noreturn` option was already provided + --> $DIR/duplicate-options.rs:24:21 + | +LL | options(noreturn), + | ^^^^^^^^ this option was already provided + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/asm/aarch64/interpolated-idents.rs b/src/test/ui/asm/aarch64/interpolated-idents.rs new file mode 100644 index 000000000..e87a88434 --- /dev/null +++ b/src/test/ui/asm/aarch64/interpolated-idents.rs @@ -0,0 +1,24 @@ +// only-aarch64 +// needs-asm-support +use std::arch::asm; + +macro_rules! m { + ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident + $pure:ident $nomem:ident $readonly:ident $preserves_flags:ident + $noreturn:ident $nostack:ident $options:ident) => { + unsafe { + asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x, + //~^ ERROR asm outputs are not allowed with the `noreturn` option + const x, sym x, + $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack)); + //~^ ERROR the `nomem` and `readonly` options are mutually exclusive + //~| ERROR the `pure` and `noreturn` options are mutually exclusive + } + }; +} + +fn main() { + m!(in out lateout inout inlateout const sym + pure nomem readonly preserves_flags + noreturn nostack options); +} diff --git a/src/test/ui/asm/aarch64/interpolated-idents.stderr b/src/test/ui/asm/aarch64/interpolated-idents.stderr new file mode 100644 index 000000000..2df17f2e0 --- /dev/null +++ b/src/test/ui/asm/aarch64/interpolated-idents.stderr @@ -0,0 +1,51 @@ +error: the `nomem` and `readonly` options are mutually exclusive + --> $DIR/interpolated-idents.rs:13:13 + | +LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / m!(in out lateout inout inlateout const sym +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack options); + | |________________________________- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: the `pure` and `noreturn` options are mutually exclusive + --> $DIR/interpolated-idents.rs:13:13 + | +LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / m!(in out lateout inout inlateout const sym +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack options); + | |________________________________- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm outputs are not allowed with the `noreturn` option + --> $DIR/interpolated-idents.rs:10:32 + | +LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x, + | ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^ +... +LL | m!(in out lateout inout inlateout const sym + | _____- + | |_____| + | |_____| + | |_____| + | | +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack options); + | | - + | |________________________________| + | |________________________________in this macro invocation + | |________________________________in this macro invocation + | |________________________________in this macro invocation + | in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/asm/aarch64/may_unwind.rs b/src/test/ui/asm/aarch64/may_unwind.rs new file mode 100644 index 000000000..ac8cc6202 --- /dev/null +++ b/src/test/ui/asm/aarch64/may_unwind.rs @@ -0,0 +1,38 @@ +// min-llvm-version: 13.0.0 +// only-aarch64 +// run-pass +// needs-asm-support + +#![feature(asm_sym, asm_unwind)] + +use std::arch::asm; +use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; + +struct Foo<'a>(&'a mut bool); + +impl Drop for Foo<'_> { + fn drop(&mut self) { + *self.0 = false; + } +} + +extern "C" fn panicky() { + resume_unwind(Box::new(())); +} + +fn main() { + let flag = &mut true; + catch_unwind(AssertUnwindSafe(|| { + let _foo = Foo(flag); + unsafe { + asm!( + "bl {}", + sym panicky, + clobber_abi("C"), + options(may_unwind) + ); + } + })) + .expect_err("expected a panic"); + assert_eq!(*flag, false); +} diff --git a/src/test/ui/asm/aarch64/parse-error.rs b/src/test/ui/asm/aarch64/parse-error.rs new file mode 100644 index 000000000..cbc93cd3f --- /dev/null +++ b/src/test/ui/asm/aarch64/parse-error.rs @@ -0,0 +1,133 @@ +// only-aarch64 + +#![feature(asm_const)] + +use std::arch::{asm, global_asm}; + +fn main() { + let mut foo = 0; + let mut bar = 0; + unsafe { + asm!(); + //~^ ERROR requires at least a template string argument + asm!(foo); + //~^ ERROR asm template must be a string literal + asm!("{}" foo); + //~^ ERROR expected token: `,` + asm!("{}", foo); + //~^ ERROR expected operand, clobber_abi, options, or additional template string + asm!("{}", in foo); + //~^ ERROR expected `(`, found `foo` + asm!("{}", in(reg foo)); + //~^ ERROR expected `)`, found `foo` + asm!("{}", in(reg)); + //~^ ERROR expected expression, found end of macro arguments + asm!("{}", inout(=) foo => bar); + //~^ ERROR expected register class or explicit register + asm!("{}", inout(reg) foo =>); + //~^ ERROR expected expression, found end of macro arguments + asm!("{}", in(reg) foo => bar); + //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` + asm!("{}", sym foo + bar); + //~^ ERROR expected a path for argument to `sym` + asm!("", options(foo)); + //~^ ERROR expected one of + asm!("", options(nomem foo)); + //~^ ERROR expected one of + asm!("", options(nomem, foo)); + //~^ ERROR expected one of + asm!("{}", options(), const foo); + //~^ ERROR arguments are not allowed after options + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", clobber_abi(foo)); + //~^ ERROR expected string literal + asm!("", clobber_abi("C" foo)); + //~^ ERROR expected one of `)` or `,`, found `foo` + asm!("", clobber_abi("C", foo)); + //~^ ERROR expected string literal + asm!("{}", clobber_abi("C"), const foo); + //~^ ERROR arguments are not allowed after clobber_abi + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", options(), clobber_abi("C")); + //~^ ERROR clobber_abi is not allowed after options + asm!("{}", options(), clobber_abi("C"), const foo); + //~^ ERROR clobber_abi is not allowed after options + asm!("{a}", a = const foo, a = const bar); + //~^ ERROR duplicate argument named `a` + //~^^ ERROR argument never used + //~^^^ ERROR attempt to use a non-constant value in a constant + //~^^^^ ERROR attempt to use a non-constant value in a constant + asm!("", a = in("x0") foo); + //~^ ERROR explicit register arguments cannot have names + asm!("{a}", in("x0") foo, a = const bar); + //~^ ERROR named arguments cannot follow explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("{a}", in("x0") foo, a = const bar); + //~^ ERROR named arguments cannot follow explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("{1}", in("x0") foo, const bar); + //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + 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 + asm!("{}", in(reg) _); + //~^ ERROR _ cannot be used for input operands + asm!("{}", inout(reg) _); + //~^ ERROR _ cannot be used for input operands + asm!("{}", inlateout(reg) _); + //~^ ERROR _ cannot be used for input operands + } +} + +const FOO: i32 = 1; +const BAR: i32 = 2; +global_asm!(); +//~^ ERROR requires at least a template string argument +global_asm!(FOO); +//~^ ERROR asm template must be a string literal +global_asm!("{}" FOO); +//~^ ERROR expected token: `,` +global_asm!("{}", FOO); +//~^ ERROR expected operand, options, or additional template string +global_asm!("{}", const); +//~^ ERROR expected expression, found end of macro arguments +global_asm!("{}", const(reg) FOO); +//~^ ERROR expected one of +global_asm!("", options(FOO)); +//~^ ERROR expected one of +global_asm!("", options(nomem FOO)); +//~^ ERROR expected one of +global_asm!("", options(nomem, FOO)); +//~^ ERROR expected one of +global_asm!("{}", options(), const FOO); +//~^ ERROR arguments are not allowed after options +global_asm!("", clobber_abi(FOO)); +//~^ ERROR expected string literal +global_asm!("", clobber_abi("C" FOO)); +//~^ ERROR expected one of `)` or `,`, found `FOO` +global_asm!("", clobber_abi("C", FOO)); +//~^ ERROR expected string literal +global_asm!("{}", clobber_abi("C"), const FOO); +//~^ ERROR arguments are not allowed after clobber_abi +//~^^ ERROR `clobber_abi` cannot be used with `global_asm!` +global_asm!("", options(), clobber_abi("C")); +//~^ ERROR clobber_abi is not allowed after options +global_asm!("{}", options(), clobber_abi("C"), const FOO); +//~^ ERROR clobber_abi is not allowed after options +global_asm!("{a}", a = const FOO, a = const BAR); +//~^ ERROR duplicate argument named `a` +//~^^ ERROR argument never used +global_asm!("", options(), ""); +//~^ ERROR expected one of +global_asm!("{}", const FOO, "{}", const FOO); +//~^ ERROR expected one of +global_asm!(format!("{{{}}}", 0), const FOO); +//~^ ERROR asm template must be a string literal +global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); +//~^ ERROR asm template must be a string literal diff --git a/src/test/ui/asm/aarch64/parse-error.stderr b/src/test/ui/asm/aarch64/parse-error.stderr new file mode 100644 index 000000000..804966b06 --- /dev/null +++ b/src/test/ui/asm/aarch64/parse-error.stderr @@ -0,0 +1,446 @@ +error: requires at least a template string argument + --> $DIR/parse-error.rs:11:9 + | +LL | asm!(); + | ^^^^^^ + +error: asm template must be a string literal + --> $DIR/parse-error.rs:13:14 + | +LL | asm!(foo); + | ^^^ + +error: expected token: `,` + --> $DIR/parse-error.rs:15:19 + | +LL | asm!("{}" foo); + | ^^^ expected `,` + +error: expected operand, clobber_abi, options, or additional template string + --> $DIR/parse-error.rs:17:20 + | +LL | asm!("{}", foo); + | ^^^ expected operand, clobber_abi, options, or additional template string + +error: expected `(`, found `foo` + --> $DIR/parse-error.rs:19:23 + | +LL | asm!("{}", in foo); + | ^^^ expected `(` + +error: expected `)`, found `foo` + --> $DIR/parse-error.rs:21:27 + | +LL | asm!("{}", in(reg foo)); + | ^^^ expected `)` + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:23:27 + | +LL | asm!("{}", in(reg)); + | ^ expected expression + +error: expected register class or explicit register + --> $DIR/parse-error.rs:25:26 + | +LL | asm!("{}", inout(=) foo => bar); + | ^ + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:27:37 + | +LL | asm!("{}", inout(reg) foo =>); + | ^ expected expression + +error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` + --> $DIR/parse-error.rs:29:32 + | +LL | asm!("{}", in(reg) foo => bar); + | ^^ expected one of 7 possible tokens + +error: expected a path for argument to `sym` + --> $DIR/parse-error.rs:31:24 + | +LL | asm!("{}", sym foo + bar); + | ^^^^^^^^^ + +error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo` + --> $DIR/parse-error.rs:33:26 + | +LL | asm!("", options(foo)); + | ^^^ expected one of 10 possible tokens + +error: expected one of `)` or `,`, found `foo` + --> $DIR/parse-error.rs:35:32 + | +LL | asm!("", options(nomem foo)); + | ^^^ expected one of `)` or `,` + +error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo` + --> $DIR/parse-error.rs:37:33 + | +LL | asm!("", options(nomem, foo)); + | ^^^ expected one of 10 possible tokens + +error: arguments are not allowed after options + --> $DIR/parse-error.rs:39:31 + | +LL | asm!("{}", options(), const foo); + | --------- ^^^^^^^^^ argument + | | + | previous options + +error: expected string literal + --> $DIR/parse-error.rs:42:30 + | +LL | asm!("", clobber_abi(foo)); + | ^^^ not a string literal + +error: expected one of `)` or `,`, found `foo` + --> $DIR/parse-error.rs:44:34 + | +LL | asm!("", clobber_abi("C" foo)); + | ^^^ expected one of `)` or `,` + +error: expected string literal + --> $DIR/parse-error.rs:46:35 + | +LL | asm!("", clobber_abi("C", foo)); + | ^^^ not a string literal + +error: arguments are not allowed after clobber_abi + --> $DIR/parse-error.rs:48:38 + | +LL | asm!("{}", clobber_abi("C"), const foo); + | ---------------- ^^^^^^^^^ argument + | | + | clobber_abi + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:51:29 + | +LL | asm!("", options(), clobber_abi("C")); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:53:31 + | +LL | asm!("{}", options(), clobber_abi("C"), const foo); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: duplicate argument named `a` + --> $DIR/parse-error.rs:55:36 + | +LL | asm!("{a}", a = const foo, a = const bar); + | ------------- ^^^^^^^^^^^^^ duplicate argument + | | + | previously here + +error: argument never used + --> $DIR/parse-error.rs:55:36 + | +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` + +error: explicit register arguments cannot have names + --> $DIR/parse-error.rs:60:18 + | +LL | asm!("", a = in("x0") foo); + | ^^^^^^^^^^^^^^^^ + +error: named arguments cannot follow explicit register arguments + --> $DIR/parse-error.rs:62:35 + | +LL | asm!("{a}", in("x0") foo, a = const bar); + | ------------ ^^^^^^^^^^^^^ named argument + | | + | explicit register argument + +error: named arguments cannot follow explicit register arguments + --> $DIR/parse-error.rs:65:35 + | +LL | asm!("{a}", in("x0") foo, a = const bar); + | ------------ ^^^^^^^^^^^^^ named argument + | | + | explicit register argument + +error: positional arguments cannot follow named arguments or explicit register arguments + --> $DIR/parse-error.rs:68:35 + | +LL | asm!("{1}", in("x0") foo, const bar); + | ------------ ^^^^^^^^^ positional argument + | | + | explicit register argument + +error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` + --> $DIR/parse-error.rs:71:29 + | +LL | asm!("", options(), ""); + | ^^ expected one of 9 possible tokens + +error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` + --> $DIR/parse-error.rs:73:33 + | +LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); + | ^^^^ expected one of 9 possible tokens + +error: asm template must be a string literal + --> $DIR/parse-error.rs:75:14 + | +LL | asm!(format!("{{{}}}", 0), in(reg) foo); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm template must be a string literal + --> $DIR/parse-error.rs:77:21 + | +LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:79:28 + | +LL | asm!("{}", in(reg) _); + | ^ + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:81:31 + | +LL | asm!("{}", inout(reg) _); + | ^ + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:83:35 + | +LL | asm!("{}", inlateout(reg) _); + | ^ + +error: requires at least a template string argument + --> $DIR/parse-error.rs:90:1 + | +LL | global_asm!(); + | ^^^^^^^^^^^^^ + +error: asm template must be a string literal + --> $DIR/parse-error.rs:92:13 + | +LL | global_asm!(FOO); + | ^^^ + +error: expected token: `,` + --> $DIR/parse-error.rs:94:18 + | +LL | global_asm!("{}" FOO); + | ^^^ expected `,` + +error: expected operand, options, or additional template string + --> $DIR/parse-error.rs:96:19 + | +LL | global_asm!("{}", FOO); + | ^^^ expected operand, options, or additional template string + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:98:24 + | +LL | global_asm!("{}", const); + | ^ expected expression + +error: expected one of `,`, `.`, `?`, or an operator, found `FOO` + --> $DIR/parse-error.rs:100:30 + | +LL | global_asm!("{}", const(reg) FOO); + | ^^^ expected one of `,`, `.`, `?`, or an operator + +error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` + --> $DIR/parse-error.rs:102:25 + | +LL | global_asm!("", options(FOO)); + | ^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/parse-error.rs:104:25 + | +LL | global_asm!("", options(nomem FOO)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/parse-error.rs:106:25 + | +LL | global_asm!("", options(nomem, FOO)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: arguments are not allowed after options + --> $DIR/parse-error.rs:108:30 + | +LL | global_asm!("{}", options(), const FOO); + | --------- ^^^^^^^^^ argument + | | + | previous options + +error: expected string literal + --> $DIR/parse-error.rs:110:29 + | +LL | global_asm!("", clobber_abi(FOO)); + | ^^^ not a string literal + +error: expected one of `)` or `,`, found `FOO` + --> $DIR/parse-error.rs:112:33 + | +LL | global_asm!("", clobber_abi("C" FOO)); + | ^^^ expected one of `)` or `,` + +error: expected string literal + --> $DIR/parse-error.rs:114:34 + | +LL | global_asm!("", clobber_abi("C", FOO)); + | ^^^ not a string literal + +error: arguments are not allowed after clobber_abi + --> $DIR/parse-error.rs:116:37 + | +LL | global_asm!("{}", clobber_abi("C"), const FOO); + | ---------------- ^^^^^^^^^ argument + | | + | clobber_abi + +error: `clobber_abi` cannot be used with `global_asm!` + --> $DIR/parse-error.rs:116:19 + | +LL | global_asm!("{}", clobber_abi("C"), const FOO); + | ^^^^^^^^^^^^^^^^ + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:119:28 + | +LL | global_asm!("", options(), clobber_abi("C")); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:121:30 + | +LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: duplicate argument named `a` + --> $DIR/parse-error.rs:123:35 + | +LL | global_asm!("{a}", a = const FOO, a = const BAR); + | ------------- ^^^^^^^^^^^^^ duplicate argument + | | + | previously here + +error: argument never used + --> $DIR/parse-error.rs:123:35 + | +LL | global_asm!("{a}", a = const FOO, a = const BAR); + | ^^^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` + +error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""` + --> $DIR/parse-error.rs:126:28 + | +LL | global_asm!("", options(), ""); + | ^^ expected one of `clobber_abi`, `const`, `options`, or `sym` + +error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"` + --> $DIR/parse-error.rs:128:30 + | +LL | global_asm!("{}", const FOO, "{}", const FOO); + | ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym` + +error: asm template must be a string literal + --> $DIR/parse-error.rs:130:13 + | +LL | global_asm!(format!("{{{}}}", 0), const FOO); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm template must be a string literal + --> $DIR/parse-error.rs:132:20 + | +LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:39:37 + | +LL | let mut foo = 0; + | ----------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{}", options(), const foo); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:48:44 + | +LL | let mut foo = 0; + | ----------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{}", clobber_abi("C"), const foo); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:55:31 + | +LL | let mut foo = 0; + | ----------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:55:46 + | +LL | let mut bar = 0; + | ----------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:62:45 + | +LL | let mut bar = 0; + | ----------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", in("x0") foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:65:45 + | +LL | let mut bar = 0; + | ----------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", in("x0") foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:68:41 + | +LL | let mut bar = 0; + | ----------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{1}", in("x0") foo, const bar); + | ^^^ non-constant value + +error: aborting due to 64 previous errors + +For more information about this error, try `rustc --explain E0435`. diff --git a/src/test/ui/asm/aarch64/srcloc.rs b/src/test/ui/asm/aarch64/srcloc.rs new file mode 100644 index 000000000..dbb6cbb94 --- /dev/null +++ b/src/test/ui/asm/aarch64/srcloc.rs @@ -0,0 +1,129 @@ +// only-aarch64 +// build-fail +// needs-asm-support +// compile-flags: -Ccodegen-units=1 + +use std::arch::asm; + +// Checks that inline asm errors are mapped to the correct line in the source code. + +fn main() { + unsafe { + asm!("invalid_instruction"); + //~^ ERROR: unrecognized instruction mnemonic + + asm!(" + invalid_instruction + "); + //~^^ ERROR: unrecognized instruction mnemonic + + asm!(r#" + invalid_instruction + "#); + //~^^ ERROR: unrecognized instruction mnemonic + + asm!(" + mov x0, x0 + invalid_instruction + mov x0, x0 + "); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!(r#" + mov x0, x0 + invalid_instruction + mov x0, x0 + "#); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!(concat!("invalid", "_", "instruction")); + //~^ ERROR: unrecognized instruction mnemonic + + asm!( + "invalid_instruction", + ); + //~^^ ERROR: unrecognized instruction mnemonic + + asm!( + "mov x0, x0", + "invalid_instruction", + "mov x0, x0", + ); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!( + "mov x0, x0\n", + "invalid_instruction", + "mov x0, x0", + ); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!( + "mov x0, x0", + concat!("invalid", "_", "instruction"), + "mov x0, x0", + ); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!( + concat!("mov x0", ", ", "x0"), + concat!("invalid", "_", "instruction"), + concat!("mov x0", ", ", "x0"), + ); + //~^^^ ERROR: unrecognized instruction mnemonic + + // Make sure template strings get separated + asm!( + "invalid_instruction1", + "invalid_instruction2", + ); + //~^^^ ERROR: unrecognized instruction mnemonic + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", + ), + ); + //~^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^ ERROR: unrecognized instruction mnemonic + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", + ), + concat!( + "invalid", "_", "instruction3", "\n", + "invalid", "_", "instruction4", + ), + ); + //~^^^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^^ ERROR: unrecognized instruction mnemonic + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", "\n", + ), + concat!( + "invalid", "_", "instruction3", "\n", + "invalid", "_", "instruction4", "\n", + ), + ); + //~^^^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^^ ERROR: unrecognized instruction mnemonic + + asm!( + "", + "\n", + "invalid_instruction" + ); + //~^^ ERROR: unrecognized instruction mnemonic + } +} diff --git a/src/test/ui/asm/aarch64/srcloc.stderr b/src/test/ui/asm/aarch64/srcloc.stderr new file mode 100644 index 000000000..2e17b60b9 --- /dev/null +++ b/src/test/ui/asm/aarch64/srcloc.stderr @@ -0,0 +1,290 @@ +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:12:15 + | +LL | asm!("invalid_instruction"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:16:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:21:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:27:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> <inline asm>:3:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:34:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> <inline asm>:3:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:39:14 + | +LL | asm!(concat!("invalid", "_", "instruction")); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:43:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:49:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:56:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:63:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:70:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:77:14 + | +LL | "invalid_instruction1", + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:78:14 + | +LL | "invalid_instruction2", + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:84:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:84:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:93:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:93:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:97:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction3 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:97:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:4:1 + | +LL | invalid_instruction4 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:108:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:108:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:112:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:4:1 + | +LL | invalid_instruction3 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:112:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:5:1 + | +LL | invalid_instruction4 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:125:14 + | +LL | "invalid_instruction" + | ^ + | +note: instantiated into assembly here + --> <inline asm>:4:1 + | +LL | invalid_instruction + | ^ + +error: aborting due to 24 previous errors + diff --git a/src/test/ui/asm/aarch64/sym.rs b/src/test/ui/asm/aarch64/sym.rs new file mode 100644 index 000000000..3f659363c --- /dev/null +++ b/src/test/ui/asm/aarch64/sym.rs @@ -0,0 +1,84 @@ +// only-aarch64 +// only-linux +// needs-asm-support +// run-pass + +#![feature(thread_local, asm_sym)] + +use std::arch::asm; + +extern "C" fn f1() -> i32 { + 111 +} + +// The compiler will generate a shim to hide the caller location parameter. +#[track_caller] +fn f2() -> i32 { + 222 +} + +macro_rules! call { + ($func:path) => { + unsafe { + let result: i32; + asm!("bl {}", sym $func, + out("w0") result, + out("x20") _, out("x21") _, out("x22") _, + out("x23") _, out("x24") _, out("x25") _, + out("x26") _, out("x27") _, out("x28") _, + ); + result + } + } +} + +macro_rules! static_addr { + ($s:expr) => { + unsafe { + let result: *const u32; + asm!( + // ADRP gives the address of a 4KB page from a PC-relative address + "adrp {out}, {sym}", + // We then add the remaining lower 12 bits + "add {out}, {out}, #:lo12:{sym}", + out = out(reg) result, + sym = sym $s); + result + } + } +} +macro_rules! static_tls_addr { + ($s:expr) => { + unsafe { + let result: *const u32; + asm!( + // Load the thread pointer register + "mrs {out}, TPIDR_EL0", + // Add the top 12 bits of the symbol's offset + "add {out}, {out}, :tprel_hi12:{sym}", + // And the bottom 12 bits + "add {out}, {out}, :tprel_lo12_nc:{sym}", + out = out(reg) result, + sym = sym $s + ); + result + } + } +} + +static S1: u32 = 111; +#[thread_local] +static S2: u32 = 222; + +fn main() { + assert_eq!(call!(f1), 111); + assert_eq!(call!(f2), 222); + assert_eq!(static_addr!(S1), &S1 as *const u32); + assert_eq!(static_tls_addr!(S2), &S2 as *const u32); + std::thread::spawn(|| { + assert_eq!(static_addr!(S1), &S1 as *const u32); + assert_eq!(static_tls_addr!(S2), &S2 as *const u32); + }) + .join() + .unwrap(); +} diff --git a/src/test/ui/asm/aarch64/type-check-2-2.rs b/src/test/ui/asm/aarch64/type-check-2-2.rs new file mode 100644 index 000000000..aa12d4aa4 --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-2-2.rs @@ -0,0 +1,37 @@ +// only-aarch64 + +#![feature(repr_simd, never_type, asm_sym)] + +use std::arch::{asm, global_asm}; + +#[repr(simd)] +#[derive(Clone, Copy)] +struct SimdType(f32, f32, f32, f32); + +#[repr(simd)] +struct SimdNonCopy(f32, f32, f32, f32); + +fn main() { + unsafe { + // Inputs must be initialized + + let x: u64; + asm!("{}", in(reg) x); + //~^ ERROR used binding `x` isn't initialized + let mut y: u64; + asm!("{}", inout(reg) y); + //~^ ERROR used binding `y` isn't initialized + let _ = y; + + // Outputs require mutable places + + let v: Vec<u64> = vec![0, 1, 2]; + asm!("{}", in(reg) v[0]); + asm!("{}", out(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + asm!("{}", inout(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + + // Sym operands must point to a function or static + } +} diff --git a/src/test/ui/asm/aarch64/type-check-2-2.stderr b/src/test/ui/asm/aarch64/type-check-2-2.stderr new file mode 100644 index 000000000..b2a695529 --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-2-2.stderr @@ -0,0 +1,38 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/type-check-2-2.rs:19:28 + | +LL | let x: u64; + | - binding declared here but left uninitialized +LL | asm!("{}", in(reg) x); + | ^ `x` used here but it isn't initialized + +error[E0381]: used binding `y` isn't initialized + --> $DIR/type-check-2-2.rs:22:9 + | +LL | let mut y: u64; + | ----- binding declared here but left uninitialized +LL | asm!("{}", inout(reg) y); + | ^^^^^^^^^^^^^^^^^^^^^^^^ `y` used here but it isn't initialized + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-2-2.rs:30:29 + | +LL | let v: Vec<u64> = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +LL | asm!("{}", in(reg) v[0]); +LL | asm!("{}", out(reg) v[0]); + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-2-2.rs:32:31 + | +LL | let v: Vec<u64> = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +... +LL | asm!("{}", inout(reg) v[0]); + | ^ cannot borrow as mutable + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0381, E0596. +For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/asm/aarch64/type-check-2.rs b/src/test/ui/asm/aarch64/type-check-2.rs new file mode 100644 index 000000000..fdafe63c7 --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-2.rs @@ -0,0 +1,76 @@ +// only-aarch64 + +#![feature(repr_simd, never_type, asm_sym)] + +use std::arch::{asm, global_asm}; + +#[repr(simd)] +#[derive(Clone, Copy)] +struct SimdType(f32, f32, f32, f32); + +#[repr(simd)] +struct SimdNonCopy(f32, f32, f32, f32); + +fn main() { + unsafe { + // Inputs must be initialized + + // Sym operands must point to a function or static + + const C: i32 = 0; + static S: i32 = 0; + asm!("{}", sym S); + asm!("{}", sym main); + asm!("{}", sym C); + //~^ ERROR invalid `sym` operand + + // Register operands must be Copy + + asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); + //~^ ERROR arguments for inline assembly must be copyable + + // Register operands must be integers, floats, SIMD vectors, pointers or + // function pointers. + + asm!("{}", in(reg) 0i64); + asm!("{}", in(reg) 0f64); + asm!("{:v}", in(vreg) SimdType(0.0, 0.0, 0.0, 0.0)); + asm!("{}", in(reg) 0 as *const u8); + asm!("{}", in(reg) 0 as *mut u8); + asm!("{}", in(reg) main as fn()); + asm!("{}", in(reg) |x: i32| x); + //~^ ERROR cannot use value of type + asm!("{}", in(reg) vec![0]); + //~^ ERROR cannot use value of type `Vec<i32>` for inline assembly + asm!("{}", in(reg) (1, 2, 3)); + //~^ ERROR cannot use value of type `(i32, i32, i32)` for inline assembly + asm!("{}", in(reg) [1, 2, 3]); + //~^ ERROR cannot use value of type `[i32; 3]` for inline assembly + + // Register inputs (but not outputs) allow references and function types + + let mut f = main; + let mut r = &mut 0; + asm!("{}", in(reg) f); + asm!("{}", inout(reg) f); + //~^ ERROR cannot use value of type `fn() {main}` for inline assembly + asm!("{}", in(reg) r); + asm!("{}", inout(reg) r); + //~^ ERROR cannot use value of type `&mut i32` for inline assembly + let _ = (f, r); + + // Type checks ignore never type + + let u: ! = unreachable!(); + asm!("{}", in(reg) u); + } +} + +// Sym operands must point to a function or static + +const C: i32 = 0; +static S: i32 = 0; +global_asm!("{}", sym S); +global_asm!("{}", sym main); +global_asm!("{}", sym C); +//~^ ERROR invalid `sym` operand diff --git a/src/test/ui/asm/aarch64/type-check-2.stderr b/src/test/ui/asm/aarch64/type-check-2.stderr new file mode 100644 index 000000000..875df44ff --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-2.stderr @@ -0,0 +1,75 @@ +error: invalid `sym` operand + --> $DIR/type-check-2.rs:75:19 + | +LL | global_asm!("{}", sym C); + | ^^^^^ is an `i32` + | + = help: `sym` operands must refer to either a function or a static + +error: invalid `sym` operand + --> $DIR/type-check-2.rs:24:20 + | +LL | asm!("{}", sym C); + | ^^^^^ is an `i32` + | + = help: `sym` operands must refer to either a function or a static + +error: arguments for inline assembly must be copyable + --> $DIR/type-check-2.rs:29:31 + | +LL | asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `SimdNonCopy` does not implement the Copy trait + +error: cannot use value of type `[closure@$DIR/type-check-2.rs:41:28: 41:36]` for inline assembly + --> $DIR/type-check-2.rs:41:28 + | +LL | asm!("{}", in(reg) |x: i32| x); + | ^^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `Vec<i32>` for inline assembly + --> $DIR/type-check-2.rs:43:28 + | +LL | asm!("{}", in(reg) vec![0]); + | ^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot use value of type `(i32, i32, i32)` for inline assembly + --> $DIR/type-check-2.rs:45:28 + | +LL | asm!("{}", in(reg) (1, 2, 3)); + | ^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `[i32; 3]` for inline assembly + --> $DIR/type-check-2.rs:47:28 + | +LL | asm!("{}", in(reg) [1, 2, 3]); + | ^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `fn() {main}` for inline assembly + --> $DIR/type-check-2.rs:55:31 + | +LL | asm!("{}", inout(reg) f); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `&mut i32` for inline assembly + --> $DIR/type-check-2.rs:58:31 + | +LL | asm!("{}", inout(reg) r); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/asm/aarch64/type-check-3.rs b/src/test/ui/asm/aarch64/type-check-3.rs new file mode 100644 index 000000000..623f6593d --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-3.rs @@ -0,0 +1,97 @@ +// only-aarch64 +// compile-flags: -C target-feature=+neon + +#![feature(repr_simd, stdsimd, asm_const)] + +use std::arch::aarch64::float64x2_t; +use std::arch::{asm, global_asm}; + +#[repr(simd)] +#[derive(Copy, Clone)] +struct Simd256bit(f64, f64, f64, f64); + +fn main() { + let f64x2: float64x2_t = unsafe { std::mem::transmute(0i128) }; + let f64x4 = Simd256bit(0.0, 0.0, 0.0, 0.0); + + unsafe { + // Types must be listed in the register class. + + // Success cases + asm!("{:w}", in(reg) 0u8); + asm!("{:w}", in(reg) 0u16); + asm!("{:w}", in(reg) 0u32); + asm!("{:w}", in(reg) 0f32); + asm!("{}", in(reg) 0i64); + asm!("{}", in(reg) 0f64); + + asm!("{:b}", in(vreg) 0u8); + asm!("{:h}", in(vreg) 0u16); + asm!("{:s}", in(vreg) 0u32); + asm!("{:s}", in(vreg) 0f32); + asm!("{:d}", in(vreg) 0u64); + asm!("{:d}", in(vreg) 0f64); + asm!("{:q}", in(vreg) f64x2); + asm!("{:v}", in(vreg) f64x2); + + // Should be the same as vreg + asm!("{:q}", in(vreg_low16) f64x2); + + // Template modifiers of a different size to the argument are fine + asm!("{:w}", in(reg) 0u64); + asm!("{:x}", in(reg) 0u32); + asm!("{:b}", in(vreg) 0u64); + asm!("{:d}", in(vreg_low16) f64x2); + + // Template modifier suggestions for sub-registers + + asm!("{}", in(reg) 0u8); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0u16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0i32); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0f32); + //~^ WARN formatting may not be suitable for sub-register argument + + asm!("{}", in(vreg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(vreg) 0f32); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(vreg) 0f64); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(vreg_low16) 0f64); + //~^ WARN formatting may not be suitable for sub-register argument + + asm!("{0} {0}", in(reg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{0} {0:x}", in(reg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + + // Invalid registers + + asm!("{}", in(reg) 0i128); + //~^ ERROR type `i128` cannot be used with this register class + asm!("{}", in(reg) f64x2); + //~^ ERROR type `float64x2_t` cannot be used with this register class + asm!("{}", in(vreg) f64x4); + //~^ ERROR type `Simd256bit` cannot be used with this register class + + // Split inout operands must have compatible types + + let mut val_i16: i16; + let mut val_f32: f32; + let mut val_u32: u32; + let mut val_u64: u64; + let mut val_ptr: *mut u8; + asm!("{:x}", inout(reg) 0u16 => val_i16); + asm!("{:x}", inout(reg) 0u32 => val_f32); + //~^ ERROR incompatible types for asm inout argument + asm!("{:x}", inout(reg) 0u32 => val_ptr); + //~^ ERROR incompatible types for asm inout argument + asm!("{:x}", inout(reg) main => val_u32); + //~^ ERROR incompatible types for asm inout argument + asm!("{:x}", inout(reg) 0u64 => val_ptr); + asm!("{:x}", inout(reg) main => val_u64); + } +} diff --git a/src/test/ui/asm/aarch64/type-check-3.stderr b/src/test/ui/asm/aarch64/type-check-3.stderr new file mode 100644 index 000000000..b320abdc0 --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-3.stderr @@ -0,0 +1,147 @@ +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:48:15 + | +LL | asm!("{}", in(reg) 0u8); + | ^^ --- for this argument + | + = note: `#[warn(asm_sub_register)]` on by default + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:50:15 + | +LL | asm!("{}", in(reg) 0u16); + | ^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:52:15 + | +LL | asm!("{}", in(reg) 0i32); + | ^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:54:15 + | +LL | asm!("{}", in(reg) 0f32); + | ^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:57:15 + | +LL | asm!("{}", in(vreg) 0i16); + | ^^ ---- for this argument + | + = help: use the `h` modifier to have the register formatted as `h0` + = help: or use the `v` modifier to keep the default formatting of `v0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:59:15 + | +LL | asm!("{}", in(vreg) 0f32); + | ^^ ---- for this argument + | + = help: use the `s` modifier to have the register formatted as `s0` + = help: or use the `v` modifier to keep the default formatting of `v0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:61:15 + | +LL | asm!("{}", in(vreg) 0f64); + | ^^ ---- for this argument + | + = help: use the `d` modifier to have the register formatted as `d0` + = help: or use the `v` modifier to keep the default formatting of `v0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:63:15 + | +LL | asm!("{}", in(vreg_low16) 0f64); + | ^^ ---- for this argument + | + = help: use the `d` modifier to have the register formatted as `d0` + = help: or use the `v` modifier to keep the default formatting of `v0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:66:15 + | +LL | asm!("{0} {0}", in(reg) 0i16); + | ^^^ ^^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:68:15 + | +LL | asm!("{0} {0:x}", in(reg) 0i16); + | ^^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +error: type `i128` cannot be used with this register class + --> $DIR/type-check-3.rs:73:28 + | +LL | asm!("{}", in(reg) 0i128); + | ^^^^^ + | + = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64 + +error: type `float64x2_t` cannot be used with this register class + --> $DIR/type-check-3.rs:75:28 + | +LL | asm!("{}", in(reg) f64x2); + | ^^^^^ + | + = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64 + +error: type `Simd256bit` cannot be used with this register class + --> $DIR/type-check-3.rs:77:29 + | +LL | asm!("{}", in(vreg) f64x4); + | ^^^^^ + | + = note: register class `vreg` supports these types: i8, i16, i32, i64, f32, f64, i8x8, i16x4, i32x2, i64x1, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:88:33 + | +LL | asm!("{:x}", inout(reg) 0u32 => val_f32); + | ^^^^ ^^^^^^^ type `f32` + | | + | type `u32` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:90:33 + | +LL | asm!("{:x}", inout(reg) 0u32 => val_ptr); + | ^^^^ ^^^^^^^ type `*mut u8` + | | + | type `u32` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:92:33 + | +LL | asm!("{:x}", inout(reg) main => val_u32); + | ^^^^ ^^^^^^^ type `u32` + | | + | type `fn()` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error: aborting due to 6 previous errors; 10 warnings emitted + diff --git a/src/test/ui/asm/aarch64/type-check-4.rs b/src/test/ui/asm/aarch64/type-check-4.rs new file mode 100644 index 000000000..bd23755c0 --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-4.rs @@ -0,0 +1,32 @@ +// only-aarch64 +// compile-flags: -C target-feature=+neon + +#![feature(repr_simd, stdsimd, asm_const)] + +use std::arch::aarch64::float64x2_t; +use std::arch::{asm, global_asm}; + +#[repr(simd)] +#[derive(Copy, Clone)] +struct Simd256bit(f64, f64, f64, f64); + +fn main() { +} + +// Constants must be... constant + +static S: i32 = 1; +const fn const_foo(x: i32) -> i32 { + x +} +const fn const_bar<T>(x: T) -> T { + x +} +global_asm!("{}", const S); +//~^ ERROR constants cannot refer to statics +global_asm!("{}", const const_foo(0)); +global_asm!("{}", const const_foo(S)); +//~^ ERROR constants cannot refer to statics +global_asm!("{}", const const_bar(0)); +global_asm!("{}", const const_bar(S)); +//~^ ERROR constants cannot refer to statics diff --git a/src/test/ui/asm/aarch64/type-check-4.stderr b/src/test/ui/asm/aarch64/type-check-4.stderr new file mode 100644 index 000000000..4837e647b --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-4.stderr @@ -0,0 +1,27 @@ +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-4.rs:25:25 + | +LL | global_asm!("{}", const S); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-4.rs:28:35 + | +LL | global_asm!("{}", const const_foo(S)); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-4.rs:31:35 + | +LL | global_asm!("{}", const const_bar(S)); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0013`. diff --git a/src/test/ui/asm/bad-arch.mirunsafeck.stderr b/src/test/ui/asm/bad-arch.mirunsafeck.stderr new file mode 100644 index 000000000..4aa271807 --- /dev/null +++ b/src/test/ui/asm/bad-arch.mirunsafeck.stderr @@ -0,0 +1,16 @@ +error[E0472]: inline assembly is unsupported on this target + --> $DIR/bad-arch.rs:22:9 + | +LL | asm!(""); + | ^^^^^^^^ + +error[E0472]: inline assembly is unsupported on this target + --> $DIR/bad-arch.rs:27:1 + | +LL | global_asm!(""); + | ^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `global_asm` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/asm/bad-arch.rs b/src/test/ui/asm/bad-arch.rs new file mode 100644 index 000000000..93309899b --- /dev/null +++ b/src/test/ui/asm/bad-arch.rs @@ -0,0 +1,28 @@ +// compile-flags: --target sparc-unknown-linux-gnu +// needs-llvm-components: sparc +// revisions: mirunsafeck thirunsafeck +// [thirunsafeck]compile-flags: -Z thir-unsafeck + +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! global_asm { + () => {}; +} +#[lang = "sized"] +trait Sized {} + +fn main() { + unsafe { + asm!(""); + //~^ ERROR inline assembly is unsupported on this target + } +} + +global_asm!(""); +//~^ ERROR inline assembly is unsupported on this target diff --git a/src/test/ui/asm/bad-arch.thirunsafeck.stderr b/src/test/ui/asm/bad-arch.thirunsafeck.stderr new file mode 100644 index 000000000..4aa271807 --- /dev/null +++ b/src/test/ui/asm/bad-arch.thirunsafeck.stderr @@ -0,0 +1,16 @@ +error[E0472]: inline assembly is unsupported on this target + --> $DIR/bad-arch.rs:22:9 + | +LL | asm!(""); + | ^^^^^^^^ + +error[E0472]: inline assembly is unsupported on this target + --> $DIR/bad-arch.rs:27:1 + | +LL | global_asm!(""); + | ^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `global_asm` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr new file mode 100644 index 000000000..7ef93e15f --- /dev/null +++ b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr @@ -0,0 +1,197 @@ +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:31:15 + | +LL | asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:33:15 + | +LL | asm!("{1}", in(reg) foo); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:33:21 + | +LL | asm!("{1}", in(reg) foo); + | ^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:36:16 + | +LL | asm!("{a}"); + | ^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:38:15 + | +LL | asm!("{}", a = in(reg) foo); + | ^^ --------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:41:15 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:41:21 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:48:15 + | +LL | asm!("{}", in("x0") foo); + | ^^ ------------ explicit register argument + | | + | from here + | + = note: no positional arguments were given +note: explicit register arguments cannot be used in the asm template + --> $DIR/bad-template.rs:48:20 + | +LL | asm!("{}", in("x0") foo); + | ^^^^^^^^^^^^ + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:50:17 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:53:18 + | +LL | asm!("", in(reg) 0, in(reg) 1); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:59:14 + | +LL | global_asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:61:14 + | +LL | global_asm!("{1}", const FOO); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:61:20 + | +LL | global_asm!("{1}", const FOO); + | ^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:64:15 + | +LL | global_asm!("{a}"); + | ^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:66:14 + | +LL | global_asm!("{}", a = const FOO); + | ^^ ------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:66:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:66:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:69:14 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:69:20 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:72:16 + | +LL | global_asm!("{:foo}", const FOO); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:74:17 + | +LL | global_asm!("", const FOO, const FOO); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/bad-template.rs:50:15 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^^^^ --- for this argument + | + = note: `#[warn(asm_sub_register)]` on by default + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +error: aborting due to 21 previous errors; 1 warning emitted + diff --git a/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr new file mode 100644 index 000000000..7ef93e15f --- /dev/null +++ b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr @@ -0,0 +1,197 @@ +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:31:15 + | +LL | asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:33:15 + | +LL | asm!("{1}", in(reg) foo); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:33:21 + | +LL | asm!("{1}", in(reg) foo); + | ^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:36:16 + | +LL | asm!("{a}"); + | ^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:38:15 + | +LL | asm!("{}", a = in(reg) foo); + | ^^ --------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:41:15 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:41:21 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:48:15 + | +LL | asm!("{}", in("x0") foo); + | ^^ ------------ explicit register argument + | | + | from here + | + = note: no positional arguments were given +note: explicit register arguments cannot be used in the asm template + --> $DIR/bad-template.rs:48:20 + | +LL | asm!("{}", in("x0") foo); + | ^^^^^^^^^^^^ + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:50:17 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:53:18 + | +LL | asm!("", in(reg) 0, in(reg) 1); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:59:14 + | +LL | global_asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:61:14 + | +LL | global_asm!("{1}", const FOO); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:61:20 + | +LL | global_asm!("{1}", const FOO); + | ^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:64:15 + | +LL | global_asm!("{a}"); + | ^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:66:14 + | +LL | global_asm!("{}", a = const FOO); + | ^^ ------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:66:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:66:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:69:14 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:69:20 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:72:16 + | +LL | global_asm!("{:foo}", const FOO); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:74:17 + | +LL | global_asm!("", const FOO, const FOO); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/bad-template.rs:50:15 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^^^^ --- for this argument + | + = note: `#[warn(asm_sub_register)]` on by default + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +error: aborting due to 21 previous errors; 1 warning emitted + diff --git a/src/test/ui/asm/bad-template.rs b/src/test/ui/asm/bad-template.rs new file mode 100644 index 000000000..556371747 --- /dev/null +++ b/src/test/ui/asm/bad-template.rs @@ -0,0 +1,75 @@ +// revisions: x86_64_mirunsafeck aarch64_mirunsafeck x86_64_thirunsafeck aarch64_thirunsafeck + +// [x86_64_thirunsafeck] compile-flags: -Z thir-unsafeck --target x86_64-unknown-linux-gnu +// [aarch64_thirunsafeck] compile-flags: -Z thir-unsafeck --target aarch64-unknown-linux-gnu +// [x86_64_mirunsafeck] compile-flags: --target x86_64-unknown-linux-gnu +// [aarch64_mirunsafeck] compile-flags: --target aarch64-unknown-linux-gnu + +// [x86_64_thirunsafeck] needs-llvm-components: x86 +// [x86_64_mirunsafeck] needs-llvm-components: x86 +// [aarch64_thirunsafeck] needs-llvm-components: aarch64 +// [aarch64_mirunsafeck] needs-llvm-components: aarch64 + +#![feature(no_core, lang_items, rustc_attrs, asm_const)] +#![no_core] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! global_asm { + () => {}; +} + +#[lang = "sized"] +trait Sized {} + +fn main() { + let mut foo = 0; + unsafe { + asm!("{}"); + //~^ ERROR invalid reference to argument at index 0 + asm!("{1}", in(reg) foo); + //~^ ERROR invalid reference to argument at index 1 + //~^^ ERROR argument never used + asm!("{a}"); + //~^ ERROR there is no argument named `a` + asm!("{}", a = in(reg) foo); + //~^ ERROR invalid reference to argument at index 0 + //~^^ ERROR argument never used + asm!("{1}", a = in(reg) foo); + //~^ ERROR invalid reference to argument at index 1 + //~^^ ERROR named argument never used + #[cfg(any(x86_64_thirunsafeck, x86_64_mirunsafeck))] + asm!("{}", in("eax") foo); + //[x86_64_thirunsafeck,x86_64_mirunsafeck]~^ ERROR invalid reference to argument at index 0 + #[cfg(any(aarch64_thirunsafeck, aarch64_mirunsafeck))] + asm!("{}", in("x0") foo); + //[aarch64_thirunsafeck,aarch64_mirunsafeck]~^ ERROR invalid reference to argument at index 0 + asm!("{:foo}", in(reg) foo); + //~^ ERROR asm template modifier must be a single character + //~| WARN formatting may not be suitable for sub-register argument [asm_sub_register] + asm!("", in(reg) 0, in(reg) 1); + //~^ ERROR multiple unused asm arguments + } +} + +const FOO: i32 = 1; +global_asm!("{}"); +//~^ ERROR invalid reference to argument at index 0 +global_asm!("{1}", const FOO); +//~^ ERROR invalid reference to argument at index 1 +//~^^ ERROR argument never used +global_asm!("{a}"); +//~^ ERROR there is no argument named `a` +global_asm!("{}", a = const FOO); +//~^ ERROR invalid reference to argument at index 0 +//~^^ ERROR argument never used +global_asm!("{1}", a = const FOO); +//~^ ERROR invalid reference to argument at index 1 +//~^^ ERROR named argument never used +global_asm!("{:foo}", const FOO); +//~^ ERROR asm template modifier must be a single character +global_asm!("", const FOO, const FOO); +//~^ ERROR multiple unused asm arguments diff --git a/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr new file mode 100644 index 000000000..250bc3be4 --- /dev/null +++ b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr @@ -0,0 +1,197 @@ +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:31:15 + | +LL | asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:33:15 + | +LL | asm!("{1}", in(reg) foo); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:33:21 + | +LL | asm!("{1}", in(reg) foo); + | ^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:36:16 + | +LL | asm!("{a}"); + | ^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:38:15 + | +LL | asm!("{}", a = in(reg) foo); + | ^^ --------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:41:15 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:41:21 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:45:15 + | +LL | asm!("{}", in("eax") foo); + | ^^ ------------- explicit register argument + | | + | from here + | + = note: no positional arguments were given +note: explicit register arguments cannot be used in the asm template + --> $DIR/bad-template.rs:45:20 + | +LL | asm!("{}", in("eax") foo); + | ^^^^^^^^^^^^^ + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:50:17 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:53:18 + | +LL | asm!("", in(reg) 0, in(reg) 1); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:59:14 + | +LL | global_asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:61:14 + | +LL | global_asm!("{1}", const FOO); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:61:20 + | +LL | global_asm!("{1}", const FOO); + | ^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:64:15 + | +LL | global_asm!("{a}"); + | ^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:66:14 + | +LL | global_asm!("{}", a = const FOO); + | ^^ ------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:66:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:66:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:69:14 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:69:20 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:72:16 + | +LL | global_asm!("{:foo}", const FOO); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:74:17 + | +LL | global_asm!("", const FOO, const FOO); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/bad-template.rs:50:15 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^^^^ --- for this argument + | + = note: `#[warn(asm_sub_register)]` on by default + = help: use the `e` modifier to have the register formatted as `eax` + = help: or use the `r` modifier to keep the default formatting of `rax` + +error: aborting due to 21 previous errors; 1 warning emitted + diff --git a/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr new file mode 100644 index 000000000..250bc3be4 --- /dev/null +++ b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr @@ -0,0 +1,197 @@ +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:31:15 + | +LL | asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:33:15 + | +LL | asm!("{1}", in(reg) foo); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:33:21 + | +LL | asm!("{1}", in(reg) foo); + | ^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:36:16 + | +LL | asm!("{a}"); + | ^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:38:15 + | +LL | asm!("{}", a = in(reg) foo); + | ^^ --------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:41:15 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:41:21 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:45:15 + | +LL | asm!("{}", in("eax") foo); + | ^^ ------------- explicit register argument + | | + | from here + | + = note: no positional arguments were given +note: explicit register arguments cannot be used in the asm template + --> $DIR/bad-template.rs:45:20 + | +LL | asm!("{}", in("eax") foo); + | ^^^^^^^^^^^^^ + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:50:17 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:53:18 + | +LL | asm!("", in(reg) 0, in(reg) 1); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:59:14 + | +LL | global_asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:61:14 + | +LL | global_asm!("{1}", const FOO); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:61:20 + | +LL | global_asm!("{1}", const FOO); + | ^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:64:15 + | +LL | global_asm!("{a}"); + | ^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:66:14 + | +LL | global_asm!("{}", a = const FOO); + | ^^ ------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:66:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:66:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:69:14 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:69:20 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:72:16 + | +LL | global_asm!("{:foo}", const FOO); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:74:17 + | +LL | global_asm!("", const FOO, const FOO); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/bad-template.rs:50:15 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^^^^ --- for this argument + | + = note: `#[warn(asm_sub_register)]` on by default + = help: use the `e` modifier to have the register formatted as `eax` + = help: or use the `r` modifier to keep the default formatting of `rax` + +error: aborting due to 21 previous errors; 1 warning emitted + diff --git a/src/test/ui/asm/generic-const.rs b/src/test/ui/asm/generic-const.rs new file mode 100644 index 000000000..55c558780 --- /dev/null +++ b/src/test/ui/asm/generic-const.rs @@ -0,0 +1,30 @@ +// needs-asm-support +// build-pass + +#![feature(asm_const, asm_sym)] + +use std::arch::asm; + +fn foofoo<const N: usize>() {} + +unsafe fn foo<const N: usize>() { + asm!("/* {0} */", const N); + asm!("/* {0} */", const N + 1); + asm!("/* {0} */", sym foofoo::<N>); +} + +fn barbar<T>() {} + +unsafe fn bar<T>() { + asm!("/* {0} */", const std::mem::size_of::<T>()); + asm!("/* {0} */", const std::mem::size_of::<(T, T)>()); + asm!("/* {0} */", sym barbar::<T>); + asm!("/* {0} */", sym barbar::<(T, T)>); +} + +fn main() { + unsafe { + foo::<0>(); + bar::<usize>(); + } +} diff --git a/src/test/ui/asm/inline-syntax.arm.stderr b/src/test/ui/asm/inline-syntax.arm.stderr new file mode 100644 index 000000000..1352fb377 --- /dev/null +++ b/src/test/ui/asm/inline-syntax.arm.stderr @@ -0,0 +1,88 @@ +error: unknown directive +.intel_syntax noprefix +^ +error: unknown directive +.intel_syntax noprefix +^ +error: unknown directive + | +note: instantiated into assembly here + --> <inline asm>:1:1 + | +LL | .intel_syntax noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:32:15 + | +LL | asm!(".intel_syntax noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .intel_syntax noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:35:15 + | +LL | asm!(".intel_syntax aaa noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .intel_syntax aaa noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:38:15 + | +LL | asm!(".att_syntax noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .att_syntax noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:41:15 + | +LL | asm!(".att_syntax bbb noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .att_syntax bbb noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:44:15 + | +LL | asm!(".intel_syntax noprefix; nop"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .intel_syntax noprefix; nop + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:50:13 + | +LL | .intel_syntax noprefix + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:13 + | +LL | .intel_syntax noprefix + | ^ + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/asm/inline-syntax.rs b/src/test/ui/asm/inline-syntax.rs new file mode 100644 index 000000000..d06796e33 --- /dev/null +++ b/src/test/ui/asm/inline-syntax.rs @@ -0,0 +1,60 @@ +// revisions: x86_64 arm +//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//[x86_64] check-pass +//[x86_64] needs-llvm-components: x86 +//[x86_64_allowed] compile-flags: --target x86_64-unknown-linux-gnu +//[x86_64_allowed] check-pass +//[x86_64_allowed] needs-llvm-components: x86 +//[arm] compile-flags: --target armv7-unknown-linux-gnueabihf +//[arm] build-fail +//[arm] needs-llvm-components: arm +// needs-asm-support + +#![feature(no_core, lang_items, rustc_attrs)] +#![crate_type = "rlib"] +#![no_core] +#![cfg_attr(x86_64_allowed, allow(bad_asm_style))] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! global_asm { + () => {}; +} + +#[lang = "sized"] +trait Sized {} + +pub fn main() { + unsafe { + asm!(".intel_syntax noprefix", "nop"); + //[x86_64]~^ WARN avoid using `.intel_syntax` + //[arm]~^^ ERROR unknown directive + asm!(".intel_syntax aaa noprefix", "nop"); + //[x86_64]~^ WARN avoid using `.intel_syntax` + //[arm]~^^ ERROR unknown directive + asm!(".att_syntax noprefix", "nop"); + //[x86_64]~^ WARN avoid using `.att_syntax` + //[arm]~^^ ERROR unknown directive + asm!(".att_syntax bbb noprefix", "nop"); + //[x86_64]~^ WARN avoid using `.att_syntax` + //[arm]~^^ ERROR unknown directive + asm!(".intel_syntax noprefix; nop"); + //[x86_64]~^ WARN avoid using `.intel_syntax` + //[arm]~^^ ERROR unknown directive + + asm!( + r" + .intel_syntax noprefix + nop" + ); + //[x86_64]~^^^ WARN avoid using `.intel_syntax` + //[arm]~^^^^ ERROR unknown directive + } +} + +global_asm!(".intel_syntax noprefix", "nop"); +//[x86_64]~^ WARN avoid using `.intel_syntax` +// Assembler errors don't have line numbers, so no error on ARM diff --git a/src/test/ui/asm/inline-syntax.x86_64.stderr b/src/test/ui/asm/inline-syntax.x86_64.stderr new file mode 100644 index 000000000..840b250f8 --- /dev/null +++ b/src/test/ui/asm/inline-syntax.x86_64.stderr @@ -0,0 +1,46 @@ +warning: avoid using `.intel_syntax`, Intel syntax is the default + --> $DIR/inline-syntax.rs:58:14 + | +LL | global_asm!(".intel_syntax noprefix", "nop"); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(bad_asm_style)]` on by default + +warning: avoid using `.intel_syntax`, Intel syntax is the default + --> $DIR/inline-syntax.rs:32:15 + | +LL | asm!(".intel_syntax noprefix", "nop"); + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: avoid using `.intel_syntax`, Intel syntax is the default + --> $DIR/inline-syntax.rs:35:15 + | +LL | asm!(".intel_syntax aaa noprefix", "nop"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead + --> $DIR/inline-syntax.rs:38:15 + | +LL | asm!(".att_syntax noprefix", "nop"); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead + --> $DIR/inline-syntax.rs:41:15 + | +LL | asm!(".att_syntax bbb noprefix", "nop"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: avoid using `.intel_syntax`, Intel syntax is the default + --> $DIR/inline-syntax.rs:44:15 + | +LL | asm!(".intel_syntax noprefix; nop"); + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: avoid using `.intel_syntax`, Intel syntax is the default + --> $DIR/inline-syntax.rs:50:13 + | +LL | .intel_syntax noprefix + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: 7 warnings emitted + diff --git a/src/test/ui/asm/issue-72570.rs b/src/test/ui/asm/issue-72570.rs new file mode 100644 index 000000000..bb1381634 --- /dev/null +++ b/src/test/ui/asm/issue-72570.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zsave-analysis +// needs-asm-support +// Also test for #72960 + +use std::arch::asm; + +fn main() { + unsafe { + asm!("", in("invalid") "".len()); + //~^ ERROR: invalid register `invalid`: unknown register + } +} diff --git a/src/test/ui/asm/issue-72570.stderr b/src/test/ui/asm/issue-72570.stderr new file mode 100644 index 000000000..fa5792688 --- /dev/null +++ b/src/test/ui/asm/issue-72570.stderr @@ -0,0 +1,8 @@ +error: invalid register `invalid`: unknown register + --> $DIR/issue-72570.rs:9:18 + | +LL | asm!("", in("invalid") "".len()); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/asm/issue-85247.rs b/src/test/ui/asm/issue-85247.rs new file mode 100644 index 000000000..e64f5e8af --- /dev/null +++ b/src/test/ui/asm/issue-85247.rs @@ -0,0 +1,26 @@ +// revisions: ropi rwpi + +// [ropi] compile-flags: --target armv7-unknown-linux-gnueabihf -C relocation-model=ropi +// [rwpi] compile-flags: --target armv7-unknown-linux-gnueabihf -C relocation-model=rwpi +// [ropi] needs-llvm-components: arm +// [rwpi] needs-llvm-components: arm +// [ropi] build-pass + +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] +#![crate_type = "rlib"] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[lang = "sized"] +trait Sized {} + +// R9 is reserved as the RWPI base register +fn main() { + unsafe { + asm!("", out("r9") _); + //[rwpi]~^ cannot use register `r9` + } +} diff --git a/src/test/ui/asm/issue-85247.rwpi.stderr b/src/test/ui/asm/issue-85247.rwpi.stderr new file mode 100644 index 000000000..996b0933a --- /dev/null +++ b/src/test/ui/asm/issue-85247.rwpi.stderr @@ -0,0 +1,8 @@ +error: cannot use register `r9`: the RWPI static base register (r9) cannot be used as an operand for inline asm + --> $DIR/issue-85247.rs:23:18 + | +LL | asm!("", out("r9") _); + | ^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/asm/issue-87802.rs b/src/test/ui/asm/issue-87802.rs new file mode 100644 index 000000000..5b2e636c2 --- /dev/null +++ b/src/test/ui/asm/issue-87802.rs @@ -0,0 +1,20 @@ +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 +// Make sure rustc doesn't ICE on asm! when output type is !. + +use std::arch::asm; + +fn hmm() -> ! { + let x; + unsafe { + asm!("/* {0} */", out(reg) x); + //~^ ERROR cannot use value of type `!` for inline assembly + } + x +} + +fn main() { + hmm(); +} diff --git a/src/test/ui/asm/issue-87802.stderr b/src/test/ui/asm/issue-87802.stderr new file mode 100644 index 000000000..de3e28fdd --- /dev/null +++ b/src/test/ui/asm/issue-87802.stderr @@ -0,0 +1,10 @@ +error: cannot use value of type `!` for inline assembly + --> $DIR/issue-87802.rs:12:36 + | +LL | asm!("/* {0} */", out(reg) x); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: aborting due to previous error + diff --git a/src/test/ui/asm/issue-89305.rs b/src/test/ui/asm/issue-89305.rs new file mode 100644 index 000000000..05677912d --- /dev/null +++ b/src/test/ui/asm/issue-89305.rs @@ -0,0 +1,16 @@ +// Regression test for #89305, where a variable was erroneously reported +// as both unused and possibly-uninitialized. + +// check-pass +// needs-asm-support + +#![warn(unused)] + +use std::arch::asm; + +fn main() { + unsafe { + let x: () = asm!("nop"); + //~^ WARNING: unused variable: `x` + } +} diff --git a/src/test/ui/asm/issue-89305.stderr b/src/test/ui/asm/issue-89305.stderr new file mode 100644 index 000000000..7efc51020 --- /dev/null +++ b/src/test/ui/asm/issue-89305.stderr @@ -0,0 +1,15 @@ +warning: unused variable: `x` + --> $DIR/issue-89305.rs:13:13 + | +LL | let x: () = asm!("nop"); + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | +note: the lint level is defined here + --> $DIR/issue-89305.rs:7:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: 1 warning emitted + diff --git a/src/test/ui/asm/issue-92378.rs b/src/test/ui/asm/issue-92378.rs new file mode 100644 index 000000000..6e3c26e98 --- /dev/null +++ b/src/test/ui/asm/issue-92378.rs @@ -0,0 +1,31 @@ +// compile-flags: --target armv5te-unknown-linux-gnueabi +// needs-llvm-components: arm +// needs-asm-support +// build-pass + +#![feature(no_core, lang_items, rustc_attrs, isa_attribute)] +#![no_core] +#![crate_type = "rlib"] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[lang = "sized"] +trait Sized {} + +// ARM uses R11 for the frame pointer, make sure R7 is usable. +#[instruction_set(arm::a32)] +pub fn arm() { + unsafe { + asm!("", out("r7") _); + } +} + +// Thumb uses R7 for the frame pointer, make sure R11 is usable. +#[instruction_set(arm::t32)] +pub fn thumb() { + unsafe { + asm!("", out("r11") _); + } +} diff --git a/src/test/ui/asm/issue-97490.rs b/src/test/ui/asm/issue-97490.rs new file mode 100644 index 000000000..37862cf34 --- /dev/null +++ b/src/test/ui/asm/issue-97490.rs @@ -0,0 +1,12 @@ +// check-pass +// only-x86_64 +// needs-asm-support + +pub type Yes = extern "sysv64" fn(&'static u8) -> !; + +fn main() { + unsafe { + let yes = &6 as *const _ as *const Yes; + core::arch::asm!("call {}", in(reg) yes, options(noreturn)); + } +} diff --git a/src/test/ui/asm/issue-99071.rs b/src/test/ui/asm/issue-99071.rs new file mode 100644 index 000000000..bb6201861 --- /dev/null +++ b/src/test/ui/asm/issue-99071.rs @@ -0,0 +1,21 @@ +// compile-flags: --target thumbv6m-none-eabi +// needs-llvm-components: arm +// needs-asm-support + +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] +#![crate_type = "rlib"] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[lang = "sized"] +trait Sized {} + +pub fn foo() { + unsafe { + asm!("", in("r8") 0); + //~^ cannot use register `r8`: high registers (r8+) can only be used as clobbers in Thumb-1 code + } +} diff --git a/src/test/ui/asm/issue-99071.stderr b/src/test/ui/asm/issue-99071.stderr new file mode 100644 index 000000000..47386ffa4 --- /dev/null +++ b/src/test/ui/asm/issue-99071.stderr @@ -0,0 +1,8 @@ +error: cannot use register `r8`: high registers (r8+) can only be used as clobbers in Thumb-1 code + --> $DIR/issue-99071.rs:18:18 + | +LL | asm!("", in("r8") 0); + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/asm/issue-99122-2.rs b/src/test/ui/asm/issue-99122-2.rs new file mode 100644 index 000000000..cfb9fd90a --- /dev/null +++ b/src/test/ui/asm/issue-99122-2.rs @@ -0,0 +1,21 @@ +// check-pass +// needs-asm-support +// only-x86_64 + +// This demonstrates why we need to erase regions before sized check in intrinsicck + +struct NoCopy; + +struct Wrap<'a, T, Tail: ?Sized>(&'a T, Tail); + +pub unsafe fn test() { + let i = NoCopy; + let j = Wrap(&i, ()); + let pointer = &j as *const _; + core::arch::asm!( + "nop", + in("eax") pointer, + ); +} + +fn main() {} diff --git a/src/test/ui/asm/issue-99122.rs b/src/test/ui/asm/issue-99122.rs new file mode 100644 index 000000000..744a563d3 --- /dev/null +++ b/src/test/ui/asm/issue-99122.rs @@ -0,0 +1,13 @@ +// needs-asm-support +// only-x86_64 + +pub unsafe fn test() { + let pointer = 1u32 as *const _; + //~^ ERROR cannot cast to a pointer of an unknown kind + core::arch::asm!( + "nop", + in("eax") pointer, + ); +} + +fn main() {} diff --git a/src/test/ui/asm/issue-99122.stderr b/src/test/ui/asm/issue-99122.stderr new file mode 100644 index 000000000..2758a4ac4 --- /dev/null +++ b/src/test/ui/asm/issue-99122.stderr @@ -0,0 +1,11 @@ +error[E0641]: cannot cast to a pointer of an unknown kind + --> $DIR/issue-99122.rs:5:27 + | +LL | let pointer = 1u32 as *const _; + | ^^^^^^^^ needs more type information + | + = note: the type information given here is insufficient to check whether the pointer cast is valid + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0641`. diff --git a/src/test/ui/asm/may_unwind.rs b/src/test/ui/asm/may_unwind.rs new file mode 100644 index 000000000..117c0a63a --- /dev/null +++ b/src/test/ui/asm/may_unwind.rs @@ -0,0 +1,11 @@ +// min-llvm-version: 13.0.0 +// run-pass +// needs-asm-support + +#![feature(asm_unwind)] + +use std::arch::asm; + +fn main() { + unsafe { asm!("", options(may_unwind)) }; +} diff --git a/src/test/ui/asm/naked-functions-ffi.rs b/src/test/ui/asm/naked-functions-ffi.rs new file mode 100644 index 000000000..c8bee504d --- /dev/null +++ b/src/test/ui/asm/naked-functions-ffi.rs @@ -0,0 +1,15 @@ +// check-pass +// needs-asm-support +#![feature(naked_functions)] +#![crate_type = "lib"] + +use std::arch::asm; + +#[naked] +pub extern "C" fn naked(p: char) -> u128 { + //~^ WARN uses type `char` + //~| WARN uses type `u128` + unsafe { + asm!("", options(noreturn)); + } +} diff --git a/src/test/ui/asm/naked-functions-ffi.stderr b/src/test/ui/asm/naked-functions-ffi.stderr new file mode 100644 index 000000000..ac7435513 --- /dev/null +++ b/src/test/ui/asm/naked-functions-ffi.stderr @@ -0,0 +1,20 @@ +warning: `extern` fn uses type `char`, which is not FFI-safe + --> $DIR/naked-functions-ffi.rs:9:28 + | +LL | pub extern "C" fn naked(p: char) -> u128 { + | ^^^^ not FFI-safe + | + = note: `#[warn(improper_ctypes_definitions)]` on by default + = help: consider using `u32` or `libc::wchar_t` instead + = note: the `char` type has no C equivalent + +warning: `extern` fn uses type `u128`, which is not FFI-safe + --> $DIR/naked-functions-ffi.rs:9:37 + | +LL | pub extern "C" fn naked(p: char) -> u128 { + | ^^^^ not FFI-safe + | + = note: 128-bit integers don't currently have a known stable ABI + +warning: 2 warnings emitted + diff --git a/src/test/ui/asm/naked-functions-unused.aarch64.stderr b/src/test/ui/asm/naked-functions-unused.aarch64.stderr new file mode 100644 index 000000000..8d3c300e0 --- /dev/null +++ b/src/test/ui/asm/naked-functions-unused.aarch64.stderr @@ -0,0 +1,69 @@ +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:17:32 + | +LL | pub extern "C" fn function(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + | +note: the lint level is defined here + --> $DIR/naked-functions-unused.rs:5:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:17:42 + | +LL | pub extern "C" fn function(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:26:38 + | +LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:26:48 + | +LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:32:41 + | +LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:32:51 + | +LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:40:40 + | +LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:40:50 + | +LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:46:43 + | +LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:46:53 + | +LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/asm/naked-functions-unused.rs b/src/test/ui/asm/naked-functions-unused.rs new file mode 100644 index 000000000..044a0e5b9 --- /dev/null +++ b/src/test/ui/asm/naked-functions-unused.rs @@ -0,0 +1,87 @@ +// revisions: x86_64 aarch64 +// needs-asm-support +//[x86_64] only-x86_64 +//[aarch64] only-aarch64 +#![deny(unused)] +#![feature(naked_functions)] +#![crate_type = "lib"] + +pub trait Trait { + extern "C" fn trait_associated(a: usize, b: usize) -> usize; + extern "C" fn trait_method(&self, a: usize, b: usize) -> usize; +} + +pub mod normal { + use std::arch::asm; + + pub extern "C" fn function(a: usize, b: usize) -> usize { + //~^ ERROR unused variable: `a` + //~| ERROR unused variable: `b` + unsafe { asm!("", options(noreturn)); } + } + + pub struct Normal; + + impl Normal { + pub extern "C" fn associated(a: usize, b: usize) -> usize { + //~^ ERROR unused variable: `a` + //~| ERROR unused variable: `b` + unsafe { asm!("", options(noreturn)); } + } + + pub extern "C" fn method(&self, a: usize, b: usize) -> usize { + //~^ ERROR unused variable: `a` + //~| ERROR unused variable: `b` + unsafe { asm!("", options(noreturn)); } + } + } + + impl super::Trait for Normal { + extern "C" fn trait_associated(a: usize, b: usize) -> usize { + //~^ ERROR unused variable: `a` + //~| ERROR unused variable: `b` + unsafe { asm!("", options(noreturn)); } + } + + extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { + //~^ ERROR unused variable: `a` + //~| ERROR unused variable: `b` + unsafe { asm!("", options(noreturn)); } + } + } +} + +pub mod naked { + use std::arch::asm; + + #[naked] + pub extern "C" fn function(a: usize, b: usize) -> usize { + unsafe { asm!("", options(noreturn)); } + } + + pub struct Naked; + + impl Naked { + #[naked] + pub extern "C" fn associated(a: usize, b: usize) -> usize { + unsafe { asm!("", options(noreturn)); } + } + + #[naked] + pub extern "C" fn method(&self, a: usize, b: usize) -> usize { + unsafe { asm!("", options(noreturn)); } + } + } + + impl super::Trait for Naked { + #[naked] + extern "C" fn trait_associated(a: usize, b: usize) -> usize { + unsafe { asm!("", options(noreturn)); } + } + + #[naked] + extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { + unsafe { asm!("", options(noreturn)); } + } + } +} diff --git a/src/test/ui/asm/naked-functions-unused.x86_64.stderr b/src/test/ui/asm/naked-functions-unused.x86_64.stderr new file mode 100644 index 000000000..8d3c300e0 --- /dev/null +++ b/src/test/ui/asm/naked-functions-unused.x86_64.stderr @@ -0,0 +1,69 @@ +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:17:32 + | +LL | pub extern "C" fn function(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + | +note: the lint level is defined here + --> $DIR/naked-functions-unused.rs:5:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:17:42 + | +LL | pub extern "C" fn function(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:26:38 + | +LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:26:48 + | +LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:32:41 + | +LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:32:51 + | +LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:40:40 + | +LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:40:50 + | +LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:46:43 + | +LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:46:53 + | +LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/asm/naked-functions.rs b/src/test/ui/asm/naked-functions.rs new file mode 100644 index 000000000..9e626f571 --- /dev/null +++ b/src/test/ui/asm/naked-functions.rs @@ -0,0 +1,218 @@ +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 + +#![feature(naked_functions)] +#![feature(asm_const, asm_sym, asm_unwind)] +#![crate_type = "lib"] + +use std::arch::asm; + +#[repr(C)] +pub struct P { + x: u8, + y: u16, +} + +#[naked] +pub unsafe extern "C" fn patterns( + mut a: u32, + //~^ ERROR patterns not allowed in naked function parameters + &b: &i32, + //~^ ERROR patterns not allowed in naked function parameters + (None | Some(_)): Option<std::ptr::NonNull<u8>>, + //~^ ERROR patterns not allowed in naked function parameters + P { x, y }: P, + //~^ ERROR patterns not allowed in naked function parameters +) { + asm!("", options(noreturn)) +} + +#[naked] +pub unsafe extern "C" fn inc(a: u32) -> u32 { + //~^ ERROR naked functions must contain a single asm block + a + 1 + //~^ ERROR referencing function parameters is not allowed in naked functions +} + +#[naked] +#[allow(asm_sub_register)] +pub unsafe extern "C" fn inc_asm(a: u32) -> u32 { + asm!("/* {0} */", in(reg) a, options(noreturn)); + //~^ ERROR referencing function parameters is not allowed in naked functions + //~| ERROR only `const` and `sym` operands are supported in naked functions +} + +#[naked] +pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { + //~^ ERROR naked functions must contain a single asm block + (|| a + 1)() +} + +#[naked] +pub unsafe extern "C" fn unsupported_operands() { + //~^ ERROR naked functions must contain a single asm block + let mut a = 0usize; + let mut b = 0usize; + let mut c = 0usize; + let mut d = 0usize; + let mut e = 0usize; + const F: usize = 0usize; + static G: usize = 0usize; + asm!("/* {0} {1} {2} {3} {4} {5} {6} */", + //~^ ERROR asm in naked functions must use `noreturn` option + in(reg) a, + //~^ ERROR only `const` and `sym` operands are supported in naked functions + inlateout(reg) b, + inout(reg) c, + lateout(reg) d, + out(reg) e, + const F, + sym G, + ); +} + +#[naked] +pub extern "C" fn missing_assembly() { + //~^ ERROR naked functions must contain a single asm block +} + +#[naked] +pub extern "C" fn too_many_asm_blocks() { + //~^ ERROR naked functions must contain a single asm block + asm!(""); + //~^ ERROR asm in naked functions must use `noreturn` option + asm!(""); + //~^ ERROR asm in naked functions must use `noreturn` option + asm!(""); + //~^ ERROR asm in naked functions must use `noreturn` option + asm!("", options(noreturn)); +} + +pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { + #[naked] + pub extern "C" fn inner(y: usize) -> usize { + //~^ ERROR naked functions must contain a single asm block + *&y + //~^ ERROR referencing function parameters is not allowed in naked functions + } + inner +} + +#[naked] +unsafe extern "C" fn invalid_options() { + asm!("", options(nomem, preserves_flags, noreturn)); + //~^ ERROR asm options unsupported in naked functions: `nomem`, `preserves_flags` +} + +#[naked] +unsafe extern "C" fn invalid_options_continued() { + asm!("", options(readonly, nostack), options(pure)); + //~^ ERROR asm with the `pure` option must have at least one output + //~| ERROR asm options unsupported in naked functions: `nostack`, `pure`, `readonly` + //~| ERROR asm in naked functions must use `noreturn` option +} + +#[naked] +unsafe extern "C" fn invalid_may_unwind() { + asm!("", options(noreturn, may_unwind)); + //~^ ERROR asm options unsupported in naked functions: `may_unwind` +} + +#[naked] +pub unsafe fn default_abi() { + //~^ WARN Rust ABI is unsupported in naked functions + asm!("", options(noreturn)); +} + +#[naked] +pub unsafe fn rust_abi() { + //~^ WARN Rust ABI is unsupported in naked functions + asm!("", options(noreturn)); +} + +#[naked] +pub extern "C" fn valid_a<T>() -> T { + unsafe { + asm!("", options(noreturn)); + } +} + +#[naked] +pub extern "C" fn valid_b() { + unsafe { + { + { + asm!("", options(noreturn)); + }; + }; + } +} + +#[naked] +pub unsafe extern "C" fn valid_c() { + asm!("", options(noreturn)); +} + +#[cfg(target_arch = "x86_64")] +#[naked] +pub unsafe extern "C" fn valid_att_syntax() { + asm!("", options(noreturn, att_syntax)); +} + +#[naked] +pub unsafe extern "C" fn inline_none() { + asm!("", options(noreturn)); +} + +#[naked] +#[inline] +//~^ ERROR naked functions cannot be inlined +pub unsafe extern "C" fn inline_hint() { + asm!("", options(noreturn)); +} + +#[naked] +#[inline(always)] +//~^ ERROR naked functions cannot be inlined +pub unsafe extern "C" fn inline_always() { + asm!("", options(noreturn)); +} + +#[naked] +#[inline(never)] +//~^ ERROR naked functions cannot be inlined +pub unsafe extern "C" fn inline_never() { + asm!("", options(noreturn)); +} + +#[naked] +#[inline] +//~^ ERROR naked functions cannot be inlined +#[inline(always)] +//~^ ERROR naked functions cannot be inlined +#[inline(never)] +//~^ ERROR naked functions cannot be inlined +pub unsafe extern "C" fn inline_all() { + asm!("", options(noreturn)); +} + +#[naked] +pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 { + compile_error!("this is a user specified error") + //~^ ERROR this is a user specified error +} + +#[naked] +pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 { + compile_error!("this is a user specified error"); + //~^ ERROR this is a user specified error + asm!("", options(noreturn)) +} + +#[naked] +pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { + asm!(invalid_syntax) + //~^ ERROR asm template must be a string literal +} diff --git a/src/test/ui/asm/naked-functions.stderr b/src/test/ui/asm/naked-functions.stderr new file mode 100644 index 000000000..1828066b6 --- /dev/null +++ b/src/test/ui/asm/naked-functions.stderr @@ -0,0 +1,303 @@ +error: asm with the `pure` option must have at least one output + --> $DIR/naked-functions.rs:111:14 + | +LL | asm!("", options(readonly, nostack), options(pure)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ + +error: this is a user specified error + --> $DIR/naked-functions.rs:203:5 + | +LL | compile_error!("this is a user specified error") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this is a user specified error + --> $DIR/naked-functions.rs:209:5 + | +LL | compile_error!("this is a user specified error"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: asm template must be a string literal + --> $DIR/naked-functions.rs:216:10 + | +LL | asm!(invalid_syntax) + | ^^^^^^^^^^^^^^ + +error: patterns not allowed in naked function parameters + --> $DIR/naked-functions.rs:20:5 + | +LL | mut a: u32, + | ^^^^^ + +error: patterns not allowed in naked function parameters + --> $DIR/naked-functions.rs:22:5 + | +LL | &b: &i32, + | ^^ + +error: patterns not allowed in naked function parameters + --> $DIR/naked-functions.rs:24:6 + | +LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>, + | ^^^^^^^^^^^^^^ + +error: patterns not allowed in naked function parameters + --> $DIR/naked-functions.rs:26:5 + | +LL | P { x, y }: P, + | ^^^^^^^^^^ + +error: referencing function parameters is not allowed in naked functions + --> $DIR/naked-functions.rs:35:5 + | +LL | a + 1 + | ^ + | + = help: follow the calling convention in asm block to use parameters + +error[E0787]: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:33:1 + | +LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 { +LL | | +LL | | a + 1 + | | ----- non-asm is unsupported in naked functions +LL | | +LL | | } + | |_^ + +error: referencing function parameters is not allowed in naked functions + --> $DIR/naked-functions.rs:42:31 + | +LL | asm!("/* {0} */", in(reg) a, options(noreturn)); + | ^ + | + = help: follow the calling convention in asm block to use parameters + +error[E0787]: only `const` and `sym` operands are supported in naked functions + --> $DIR/naked-functions.rs:42:23 + | +LL | asm!("/* {0} */", in(reg) a, options(noreturn)); + | ^^^^^^^^^ + +error[E0787]: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:48:1 + | +LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { +LL | | +LL | | (|| a + 1)() + | | ------------ non-asm is unsupported in naked functions +LL | | } + | |_^ + +error[E0787]: only `const` and `sym` operands are supported in naked functions + --> $DIR/naked-functions.rs:65:10 + | +LL | in(reg) a, + | ^^^^^^^^^ +LL | +LL | inlateout(reg) b, + | ^^^^^^^^^^^^^^^^ +LL | inout(reg) c, + | ^^^^^^^^^^^^ +LL | lateout(reg) d, + | ^^^^^^^^^^^^^^ +LL | out(reg) e, + | ^^^^^^^^^^ + +error[E0787]: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:63:5 + | +LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */", +LL | | +LL | | in(reg) a, +LL | | +... | +LL | | sym G, +LL | | ); + | |_____^ + | +help: consider specifying that the asm block is responsible for returning from the function + | +LL | sym G, options(noreturn), + | +++++++++++++++++++ + +error[E0787]: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:54:1 + | +LL | / pub unsafe extern "C" fn unsupported_operands() { +LL | | +LL | | let mut a = 0usize; + | | ------------------- non-asm is unsupported in naked functions +LL | | let mut b = 0usize; + | | ------------------- non-asm is unsupported in naked functions +LL | | let mut c = 0usize; + | | ------------------- non-asm is unsupported in naked functions +LL | | let mut d = 0usize; + | | ------------------- non-asm is unsupported in naked functions +LL | | let mut e = 0usize; + | | ------------------- non-asm is unsupported in naked functions +... | +LL | | ); +LL | | } + | |_^ + +error[E0787]: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:77:1 + | +LL | / pub extern "C" fn missing_assembly() { +LL | | +LL | | } + | |_^ + +error[E0787]: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:84:5 + | +LL | asm!(""); + | ^^^^^^^^ + | +help: consider specifying that the asm block is responsible for returning from the function + | +LL | asm!("", options(noreturn)); + | +++++++++++++++++++ + +error[E0787]: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:86:5 + | +LL | asm!(""); + | ^^^^^^^^ + | +help: consider specifying that the asm block is responsible for returning from the function + | +LL | asm!("", options(noreturn)); + | +++++++++++++++++++ + +error[E0787]: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:88:5 + | +LL | asm!(""); + | ^^^^^^^^ + | +help: consider specifying that the asm block is responsible for returning from the function + | +LL | asm!("", options(noreturn)); + | +++++++++++++++++++ + +error[E0787]: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:82:1 + | +LL | / pub extern "C" fn too_many_asm_blocks() { +LL | | +LL | | asm!(""); +LL | | +LL | | asm!(""); + | | -------- multiple asm blocks are unsupported in naked functions +LL | | +LL | | asm!(""); + | | -------- multiple asm blocks are unsupported in naked functions +LL | | +LL | | asm!("", options(noreturn)); + | | --------------------------- multiple asm blocks are unsupported in naked functions +LL | | } + | |_^ + +error: referencing function parameters is not allowed in naked functions + --> $DIR/naked-functions.rs:97:11 + | +LL | *&y + | ^ + | + = help: follow the calling convention in asm block to use parameters + +error[E0787]: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:95:5 + | +LL | / pub extern "C" fn inner(y: usize) -> usize { +LL | | +LL | | *&y + | | --- non-asm is unsupported in naked functions +LL | | +LL | | } + | |_____^ + +error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags` + --> $DIR/naked-functions.rs:105:5 + | +LL | asm!("", options(nomem, preserves_flags, noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0787]: asm options unsupported in naked functions: `nostack`, `pure`, `readonly` + --> $DIR/naked-functions.rs:111:5 + | +LL | asm!("", options(readonly, nostack), options(pure)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0787]: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:111:5 + | +LL | asm!("", options(readonly, nostack), options(pure)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider specifying that the asm block is responsible for returning from the function + | +LL | asm!("", options(noreturn), options(readonly, nostack), options(pure)); + | +++++++++++++++++++ + +error[E0787]: asm options unsupported in naked functions: `may_unwind` + --> $DIR/naked-functions.rs:119:5 + | +LL | asm!("", options(noreturn, may_unwind)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: Rust ABI is unsupported in naked functions + --> $DIR/naked-functions.rs:124:15 + | +LL | pub unsafe fn default_abi() { + | ^^^^^^^^^^^ + | + = note: `#[warn(undefined_naked_function_abi)]` on by default + +warning: Rust ABI is unsupported in naked functions + --> $DIR/naked-functions.rs:130:15 + | +LL | pub unsafe fn rust_abi() { + | ^^^^^^^^ + +error: naked functions cannot be inlined + --> $DIR/naked-functions.rs:170:1 + | +LL | #[inline] + | ^^^^^^^^^ + +error: naked functions cannot be inlined + --> $DIR/naked-functions.rs:177:1 + | +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ + +error: naked functions cannot be inlined + --> $DIR/naked-functions.rs:184:1 + | +LL | #[inline(never)] + | ^^^^^^^^^^^^^^^^ + +error: naked functions cannot be inlined + --> $DIR/naked-functions.rs:191:1 + | +LL | #[inline] + | ^^^^^^^^^ + +error: naked functions cannot be inlined + --> $DIR/naked-functions.rs:193:1 + | +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ + +error: naked functions cannot be inlined + --> $DIR/naked-functions.rs:195:1 + | +LL | #[inline(never)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 33 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0787`. diff --git a/src/test/ui/asm/naked-invalid-attr.rs b/src/test/ui/asm/naked-invalid-attr.rs new file mode 100644 index 000000000..ea8f560ff --- /dev/null +++ b/src/test/ui/asm/naked-invalid-attr.rs @@ -0,0 +1,52 @@ +// Checks that #[naked] attribute can be placed on function definitions only. +// +// needs-asm-support +#![feature(naked_functions)] +#![naked] //~ ERROR should be applied to a function definition + +use std::arch::asm; + +extern "C" { + #[naked] //~ ERROR should be applied to a function definition + fn f(); +} + +#[naked] //~ ERROR should be applied to a function definition +#[repr(C)] +struct S { + a: u32, + b: u32, +} + +trait Invoke { + #[naked] //~ ERROR should be applied to a function definition + extern "C" fn invoke(&self); +} + +impl Invoke for S { + #[naked] + extern "C" fn invoke(&self) { + unsafe { asm!("", options(noreturn)) } + } +} + +#[naked] +extern "C" fn ok() { + unsafe { asm!("", options(noreturn)) } +} + +impl S { + #[naked] + extern "C" fn g() { + unsafe { asm!("", options(noreturn)) } + } + + #[naked] + extern "C" fn h(&self) { + unsafe { asm!("", options(noreturn)) } + } +} + +fn main() { + #[naked] || {}; //~ ERROR should be applied to a function definition +} diff --git a/src/test/ui/asm/naked-invalid-attr.stderr b/src/test/ui/asm/naked-invalid-attr.stderr new file mode 100644 index 000000000..58344be93 --- /dev/null +++ b/src/test/ui/asm/naked-invalid-attr.stderr @@ -0,0 +1,42 @@ +error: attribute should be applied to a function definition + --> $DIR/naked-invalid-attr.rs:14:1 + | +LL | #[naked] + | ^^^^^^^^ +LL | #[repr(C)] +LL | / struct S { +LL | | a: u32, +LL | | b: u32, +LL | | } + | |_- not a function definition + +error: attribute should be applied to a function definition + --> $DIR/naked-invalid-attr.rs:51:5 + | +LL | #[naked] || {}; + | ^^^^^^^^ ----- not a function definition + +error: attribute should be applied to a function definition + --> $DIR/naked-invalid-attr.rs:22:5 + | +LL | #[naked] + | ^^^^^^^^ +LL | extern "C" fn invoke(&self); + | ---------------------------- not a function definition + +error: attribute should be applied to a function definition + --> $DIR/naked-invalid-attr.rs:10:5 + | +LL | #[naked] + | ^^^^^^^^ +LL | fn f(); + | ------- not a function definition + +error: attribute should be applied to a function definition + --> $DIR/naked-invalid-attr.rs:5:1 + | +LL | #![naked] + | ^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/asm/named-asm-labels.rs b/src/test/ui/asm/named-asm-labels.rs new file mode 100644 index 000000000..160dbf617 --- /dev/null +++ b/src/test/ui/asm/named-asm-labels.rs @@ -0,0 +1,196 @@ +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 + +// Tests that the use of named labels in the `asm!` macro are linted against +// except for in `#[naked]` fns. +// Using a named label is incorrect as per the RFC because for most cases +// the compiler cannot ensure that inline asm is emitted exactly once per +// codegen unit (except for naked fns) and so the label could be duplicated +// which causes less readable LLVM errors and in the worst cases causes ICEs +// or segfaults based on system dependent behavior and codegen flags. + +#![feature(naked_functions, asm_const)] + +use std::arch::{asm, global_asm}; + +#[no_mangle] +pub static FOO: usize = 42; + +fn main() { + unsafe { + // Basic usage + asm!("bar: nop"); //~ ERROR avoid using named labels + + // No following asm + asm!("abcd:"); //~ ERROR avoid using named labels + + // Multiple labels on one line + asm!("foo: bar1: nop"); + //~^ ERROR avoid using named labels + + // Multiple lines + asm!("foo1: nop", "nop"); //~ ERROR avoid using named labels + asm!("foo2: foo3: nop", "nop"); + //~^ ERROR avoid using named labels + asm!("nop", "foo4: nop"); //~ ERROR avoid using named labels + asm!("foo5: nop", "foo6: nop"); + //~^ ERROR avoid using named labels + //~| ERROR avoid using named labels + + // Statement separator + asm!("foo7: nop; foo8: nop"); + //~^ ERROR avoid using named labels + asm!("foo9: nop; nop"); //~ ERROR avoid using named labels + asm!("nop; foo10: nop"); //~ ERROR avoid using named labels + + // Escaped newline + asm!("bar2: nop\n bar3: nop"); + //~^ ERROR avoid using named labels + asm!("bar4: nop\n nop"); //~ ERROR avoid using named labels + asm!("nop\n bar5: nop"); //~ ERROR avoid using named labels + asm!("nop\n bar6: bar7: nop"); + //~^ ERROR avoid using named labels + + // Raw strings + asm!( + r" + blah2: nop + blah3: nop + " + ); + //~^^^^ ERROR avoid using named labels + + asm!( + r###" + nop + nop ; blah4: nop + "### + ); + //~^^^ ERROR avoid using named labels + + // Non-labels + // should not trigger lint, but may be invalid asm + asm!("ab cd: nop"); + + // `blah:` does not trigger because labels need to be at the start + // of the statement, and there was already a non-label + asm!("1bar: blah: nop"); + + // Only `blah1:` should trigger + asm!("blah1: 2bar: nop"); //~ ERROR avoid using named labels + + // Duplicate labels + asm!("def: def: nop"); //~ ERROR avoid using named labels + asm!("def: nop\ndef: nop"); //~ ERROR avoid using named labels + asm!("def: nop; def: nop"); //~ ERROR avoid using named labels + + // Trying to break parsing + asm!(":"); + asm!("\n:\n"); + asm!("::::"); + + // 0x3A is a ':' + asm!("fooo\u{003A} nop"); //~ ERROR avoid using named labels + asm!("foooo\x3A nop"); //~ ERROR avoid using named labels + + // 0x0A is a newline + asm!("fooooo:\u{000A} nop"); //~ ERROR avoid using named labels + asm!("foooooo:\x0A nop"); //~ ERROR avoid using named labels + + // Intentionally breaking span finding + // equivalent to "ABC: nop" + asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); //~ ERROR avoid using named labels + + // Non-label colons - should pass + asm!("mov rax, qword ptr fs:[0]"); + + // Comments + asm!( + r" + ab: nop // ab: does foo + // cd: nop + " + ); + //~^^^^ ERROR avoid using named labels + + // Tests usage of colons in non-label positions + asm!(":lo12:FOO"); // this is apparently valid aarch64 + // is there an example that is valid x86 for this test? + asm!(":bbb nop"); + + // Test include_str in asm + asm!(include_str!("named-asm-labels.s")); //~ ERROR avoid using named labels + + // Test allowing or warning on the lint instead + #[allow(named_asm_labels)] + { + asm!("allowed: nop"); // Should not emit anything + } + + #[warn(named_asm_labels)] + { + asm!("warned: nop"); //~ WARNING avoid using named labels + } + } +} + +// Trigger on naked fns too, even though they can't be inlined, reusing a +// label or LTO can cause labels to break +#[naked] +pub extern "C" fn foo() -> i32 { + unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } //~ ERROR avoid using named labels +} + +// Make sure that non-naked attributes *do* still let the lint happen +#[no_mangle] +pub extern "C" fn bar() { + unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } + //~^ ERROR avoid using named labels +} + +#[naked] +pub extern "C" fn aaa() { + fn _local() {} + + unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } //~ ERROR avoid using named labels +} + +pub fn normal() { + fn _local1() {} + + #[naked] + pub extern "C" fn bbb() { + fn _very_local() {} + + unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } //~ ERROR avoid using named labels + } + + fn _local2() {} +} + +// Make sure that the lint happens within closures +fn closures() { + || unsafe { + asm!("closure1: nop"); //~ ERROR avoid using named labels + }; + + move || unsafe { + asm!("closure2: nop"); //~ ERROR avoid using named labels + }; + + || { + #[naked] + unsafe extern "C" fn _nested() { + asm!("ret;", options(noreturn)); + } + + unsafe { + asm!("closure3: nop"); //~ ERROR avoid using named labels + } + }; +} + +// Don't trigger on global asm +global_asm!("aaaaaaaa: nop"); diff --git a/src/test/ui/asm/named-asm-labels.s b/src/test/ui/asm/named-asm-labels.s new file mode 100644 index 000000000..071356d75 --- /dev/null +++ b/src/test/ui/asm/named-asm-labels.s @@ -0,0 +1,5 @@ +lab1: nop +// do more things +lab2: nop // does bar +// a: b +lab3: nop; lab4: nop diff --git a/src/test/ui/asm/named-asm-labels.stderr b/src/test/ui/asm/named-asm-labels.stderr new file mode 100644 index 000000000..001601497 --- /dev/null +++ b/src/test/ui/asm/named-asm-labels.stderr @@ -0,0 +1,334 @@ +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:24:15 + | +LL | asm!("bar: nop"); + | ^^^ + | + = note: `#[deny(named_asm_labels)]` on by default + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:27:15 + | +LL | asm!("abcd:"); + | ^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:30:15 + | +LL | asm!("foo: bar1: nop"); + | ^^^ ^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:34:15 + | +LL | asm!("foo1: nop", "nop"); + | ^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:35:15 + | +LL | asm!("foo2: foo3: nop", "nop"); + | ^^^^ ^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:37:22 + | +LL | asm!("nop", "foo4: nop"); + | ^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:38:15 + | +LL | asm!("foo5: nop", "foo6: nop"); + | ^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:38:28 + | +LL | asm!("foo5: nop", "foo6: nop"); + | ^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:43:15 + | +LL | asm!("foo7: nop; foo8: nop"); + | ^^^^ ^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:45:15 + | +LL | asm!("foo9: nop; nop"); + | ^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:46:20 + | +LL | asm!("nop; foo10: nop"); + | ^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:49:15 + | +LL | asm!("bar2: nop\n bar3: nop"); + | ^^^^ ^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:51:15 + | +LL | asm!("bar4: nop\n nop"); + | ^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:52:21 + | +LL | asm!("nop\n bar5: nop"); + | ^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:53:21 + | +LL | asm!("nop\n bar6: bar7: nop"); + | ^^^^ ^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:59:13 + | +LL | blah2: nop + | ^^^^^ +LL | blah3: nop + | ^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:68:19 + | +LL | nop ; blah4: nop + | ^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:82:15 + | +LL | asm!("blah1: 2bar: nop"); + | ^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:85:15 + | +LL | asm!("def: def: nop"); + | ^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:86:15 + | +LL | asm!("def: nop\ndef: nop"); + | ^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:87:15 + | +LL | asm!("def: nop; def: nop"); + | ^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:95:15 + | +LL | asm!("fooo\u{003A} nop"); + | ^^^^^^^^^^^^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:96:15 + | +LL | asm!("foooo\x3A nop"); + | ^^^^^^^^^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:99:15 + | +LL | asm!("fooooo:\u{000A} nop"); + | ^^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:100:15 + | +LL | asm!("foooooo:\x0A nop"); + | ^^^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:104:14 + | +LL | asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:112:13 + | +LL | ab: nop // ab: does foo + | ^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:124:14 + | +LL | asm!(include_str!("named-asm-labels.s")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +warning: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:134:19 + | +LL | asm!("warned: nop"); + | ^^^^^^ + | +note: the lint level is defined here + --> $DIR/named-asm-labels.rs:132:16 + | +LL | #[warn(named_asm_labels)] + | ^^^^^^^^^^^^^^^^ + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:143:20 + | +LL | unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } + | ^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:149:20 + | +LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } + | ^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:157:20 + | +LL | unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) } + | ^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:167:24 + | +LL | unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } + | ^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:176:15 + | +LL | asm!("closure1: nop"); + | ^^^^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:180:15 + | +LL | asm!("closure2: nop"); + | ^^^^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: avoid using named labels in inline assembly + --> $DIR/named-asm-labels.rs:190:19 + | +LL | asm!("closure3: nop"); + | ^^^^^^^^ + | + = help: only local labels of the form `<number>:` should be used in inline asm + = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information + +error: aborting due to 35 previous errors; 1 warning emitted + diff --git a/src/test/ui/asm/noreturn.rs b/src/test/ui/asm/noreturn.rs new file mode 100644 index 000000000..03fa087ae --- /dev/null +++ b/src/test/ui/asm/noreturn.rs @@ -0,0 +1,19 @@ +// needs-asm-support +// check-pass + +#![feature(never_type)] +#![crate_type = "rlib"] + +use std::arch::asm; + +pub unsafe fn asm1() { + let _: () = asm!(""); +} + +pub unsafe fn asm2() { + let _: ! = asm!("", options(noreturn)); +} + +pub unsafe fn asm3() -> ! { + asm!("", options(noreturn)); +} diff --git a/src/test/ui/asm/reg-conflict.rs b/src/test/ui/asm/reg-conflict.rs new file mode 100644 index 000000000..983788a93 --- /dev/null +++ b/src/test/ui/asm/reg-conflict.rs @@ -0,0 +1,20 @@ +// compile-flags: --target armv7-unknown-linux-gnueabihf +// needs-llvm-components: arm + +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[lang = "sized"] +trait Sized {} + +fn main() { + unsafe { + asm!("", out("d0") _, out("d1") _); + asm!("", out("d0") _, out("s1") _); + //~^ ERROR register `s1` conflicts with register `d0` + } +} diff --git a/src/test/ui/asm/reg-conflict.stderr b/src/test/ui/asm/reg-conflict.stderr new file mode 100644 index 000000000..2395566de --- /dev/null +++ b/src/test/ui/asm/reg-conflict.stderr @@ -0,0 +1,10 @@ +error: register `s1` conflicts with register `d0` + --> $DIR/reg-conflict.rs:17:31 + | +LL | asm!("", out("d0") _, out("s1") _); + | ----------- ^^^^^^^^^^^ register `s1` + | | + | register `d0` + +error: aborting due to previous error + diff --git a/src/test/ui/asm/type-check-1.rs b/src/test/ui/asm/type-check-1.rs new file mode 100644 index 000000000..50b369ae0 --- /dev/null +++ b/src/test/ui/asm/type-check-1.rs @@ -0,0 +1,79 @@ +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 + +#![feature(asm_const, asm_sym)] + +use std::arch::{asm, global_asm}; + +fn main() { + unsafe { + // Outputs must be place expressions + + asm!("{}", in(reg) 1 + 2); + asm!("{}", out(reg) 1 + 2); + //~^ ERROR invalid asm output + asm!("{}", inout(reg) 1 + 2); + //~^ ERROR invalid asm output + + // Operands must be sized + + let v: [u64; 3] = [0, 1, 2]; + asm!("{}", in(reg) v[..]); + //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time + //~| ERROR cannot use value of type `[u64]` for inline assembly + asm!("{}", out(reg) v[..]); + //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time + //~| ERROR cannot use value of type `[u64]` for inline assembly + asm!("{}", inout(reg) v[..]); + //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time + //~| ERROR cannot use value of type `[u64]` for inline assembly + + // Constants must be... constant + + let x = 0; + const fn const_foo(x: i32) -> i32 { + x + } + const fn const_bar<T>(x: T) -> T { + x + } + asm!("{}", const x); + //~^ ERROR attempt to use a non-constant value in a constant + asm!("{}", const const_foo(0)); + asm!("{}", const const_foo(x)); + //~^ ERROR attempt to use a non-constant value in a constant + asm!("{}", const const_bar(0)); + asm!("{}", const const_bar(x)); + //~^ ERROR attempt to use a non-constant value in a constant + asm!("{}", sym x); + //~^ ERROR invalid `sym` operand + + // Const operands must be integers and must be constants. + + asm!("{}", const 0); + asm!("{}", const 0i32); + asm!("{}", const 0i128); + asm!("{}", const 0f32); + //~^ ERROR mismatched types + asm!("{}", const 0 as *mut u8); + //~^ ERROR mismatched types + asm!("{}", const &0); + //~^ ERROR mismatched types + } +} + +unsafe fn generic<T>() { + asm!("{}", sym generic::<T>); +} + +// Const operands must be integers and must be constants. + +global_asm!("{}", const 0); +global_asm!("{}", const 0i32); +global_asm!("{}", const 0i128); +global_asm!("{}", const 0f32); +//~^ ERROR mismatched types +global_asm!("{}", const 0 as *mut u8); +//~^ ERROR mismatched types diff --git a/src/test/ui/asm/type-check-1.stderr b/src/test/ui/asm/type-check-1.stderr new file mode 100644 index 000000000..162ff1d32 --- /dev/null +++ b/src/test/ui/asm/type-check-1.stderr @@ -0,0 +1,144 @@ +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/type-check-1.rs:42:26 + | +LL | let x = 0; + | ----- help: consider using `const` instead of `let`: `const x` +... +LL | asm!("{}", const x); + | ^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/type-check-1.rs:45:36 + | +LL | let x = 0; + | ----- help: consider using `const` instead of `let`: `const x` +... +LL | asm!("{}", const const_foo(x)); + | ^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/type-check-1.rs:48:36 + | +LL | let x = 0; + | ----- help: consider using `const` instead of `let`: `const x` +... +LL | asm!("{}", const const_bar(x)); + | ^ non-constant value + +error: invalid `sym` operand + --> $DIR/type-check-1.rs:50:24 + | +LL | asm!("{}", sym x); + | ^ is a local variable + | + = help: `sym` operands must refer to either a function or a static + +error: invalid asm output + --> $DIR/type-check-1.rs:15:29 + | +LL | asm!("{}", out(reg) 1 + 2); + | ^^^^^ cannot assign to this expression + +error: invalid asm output + --> $DIR/type-check-1.rs:17:31 + | +LL | asm!("{}", inout(reg) 1 + 2); + | ^^^^^ cannot assign to this expression + +error[E0277]: the size for values of type `[u64]` cannot be known at compilation time + --> $DIR/type-check-1.rs:23:28 + | +LL | asm!("{}", in(reg) v[..]); + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u64]` + = note: all inline asm arguments must have a statically known size + +error[E0277]: the size for values of type `[u64]` cannot be known at compilation time + --> $DIR/type-check-1.rs:26:29 + | +LL | asm!("{}", out(reg) v[..]); + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u64]` + = note: all inline asm arguments must have a statically known size + +error[E0277]: the size for values of type `[u64]` cannot be known at compilation time + --> $DIR/type-check-1.rs:29:31 + | +LL | asm!("{}", inout(reg) v[..]); + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u64]` + = note: all inline asm arguments must have a statically known size + +error: cannot use value of type `[u64]` for inline assembly + --> $DIR/type-check-1.rs:23:28 + | +LL | asm!("{}", in(reg) v[..]); + | ^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `[u64]` for inline assembly + --> $DIR/type-check-1.rs:26:29 + | +LL | asm!("{}", out(reg) v[..]); + | ^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `[u64]` for inline assembly + --> $DIR/type-check-1.rs:29:31 + | +LL | asm!("{}", inout(reg) v[..]); + | ^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error[E0308]: mismatched types + --> $DIR/type-check-1.rs:58:26 + | +LL | asm!("{}", const 0f32); + | ^^^^ expected integer, found `f32` + +error[E0308]: mismatched types + --> $DIR/type-check-1.rs:60:26 + | +LL | asm!("{}", const 0 as *mut u8); + | ^^^^^^^^^^^^ expected integer, found *-ptr + | + = note: expected type `{integer}` + found raw pointer `*mut u8` + +error[E0308]: mismatched types + --> $DIR/type-check-1.rs:62:26 + | +LL | asm!("{}", const &0); + | ^^ expected integer, found `&{integer}` + | +help: consider removing the borrow + | +LL - asm!("{}", const &0); +LL + asm!("{}", const 0); + | + +error[E0308]: mismatched types + --> $DIR/type-check-1.rs:76:25 + | +LL | global_asm!("{}", const 0f32); + | ^^^^ expected integer, found `f32` + +error[E0308]: mismatched types + --> $DIR/type-check-1.rs:78:25 + | +LL | global_asm!("{}", const 0 as *mut u8); + | ^^^^^^^^^^^^ expected integer, found *-ptr + | + = note: expected type `{integer}` + found raw pointer `*mut u8` + +error: aborting due to 17 previous errors + +Some errors have detailed explanations: E0277, E0308, E0435. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/asm/type-check-4.rs b/src/test/ui/asm/type-check-4.rs new file mode 100644 index 000000000..666d2c677 --- /dev/null +++ b/src/test/ui/asm/type-check-4.rs @@ -0,0 +1,26 @@ +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 + +use std::arch::asm; + +fn main() { + unsafe { + // Can't output to borrowed values. + + let mut a = 0isize; + let p = &a; + asm!("{}", out(reg) a); + //~^ cannot assign to `a` because it is borrowed + println!("{}", p); + + // Can't read from mutable borrowed values. + + let mut a = 0isize; + let p = &mut a; + asm!("{}", in(reg) a); + //~^ cannot use `a` because it was mutably borrowed + println!("{}", p); + } +} diff --git a/src/test/ui/asm/type-check-4.stderr b/src/test/ui/asm/type-check-4.stderr new file mode 100644 index 000000000..c97cd171b --- /dev/null +++ b/src/test/ui/asm/type-check-4.stderr @@ -0,0 +1,26 @@ +error[E0506]: cannot assign to `a` because it is borrowed + --> $DIR/type-check-4.rs:14:9 + | +LL | let p = &a; + | -- borrow of `a` occurs here +LL | asm!("{}", out(reg) a); + | ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `a` occurs here +LL | +LL | println!("{}", p); + | - borrow later used here + +error[E0503]: cannot use `a` because it was mutably borrowed + --> $DIR/type-check-4.rs:22:28 + | +LL | let p = &mut a; + | ------ borrow of `a` occurs here +LL | asm!("{}", in(reg) a); + | ^ use of borrowed `a` +LL | +LL | println!("{}", p); + | - borrow later used here + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0503, E0506. +For more information about an error, try `rustc --explain E0503`. diff --git a/src/test/ui/asm/x86_64/bad-clobber-abi.rs b/src/test/ui/asm/x86_64/bad-clobber-abi.rs new file mode 100644 index 000000000..ddcd2065b --- /dev/null +++ b/src/test/ui/asm/x86_64/bad-clobber-abi.rs @@ -0,0 +1,32 @@ +// needs-asm-support +// only-x86_64 + +use std::arch::asm; + +// checks various modes of failure for the `clobber_abi` argument (after parsing) + +fn main() { + unsafe { + asm!("", clobber_abi("C")); + asm!("", clobber_abi("foo")); + //~^ ERROR invalid ABI for `clobber_abi` + asm!("", clobber_abi("C", "foo")); + //~^ ERROR invalid ABI for `clobber_abi` + asm!("", clobber_abi("C", "C")); + //~^ ERROR `C` ABI specified multiple times + asm!("", clobber_abi("win64", "sysv64")); + asm!("", clobber_abi("win64", "efiapi")); + //~^ ERROR `win64` ABI specified multiple times + asm!("", clobber_abi("C", "foo", "C")); + //~^ ERROR invalid ABI for `clobber_abi` + //~| ERROR `C` ABI specified multiple times + asm!("", clobber_abi("win64", "foo", "efiapi")); + //~^ ERROR invalid ABI for `clobber_abi` + //~| ERROR `win64` ABI specified multiple times + asm!("", clobber_abi("C"), clobber_abi("C")); + //~^ ERROR `C` ABI specified multiple times + asm!("", clobber_abi("win64"), clobber_abi("sysv64")); + asm!("", clobber_abi("win64"), clobber_abi("efiapi")); + //~^ ERROR `win64` ABI specified multiple times + } +} diff --git a/src/test/ui/asm/x86_64/bad-clobber-abi.stderr b/src/test/ui/asm/x86_64/bad-clobber-abi.stderr new file mode 100644 index 000000000..46e91a395 --- /dev/null +++ b/src/test/ui/asm/x86_64/bad-clobber-abi.stderr @@ -0,0 +1,88 @@ +error: invalid ABI for `clobber_abi` + --> $DIR/bad-clobber-abi.rs:11:18 + | +LL | asm!("", clobber_abi("foo")); + | ^^^^^^^^^^^^^^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + +error: invalid ABI for `clobber_abi` + --> $DIR/bad-clobber-abi.rs:13:35 + | +LL | asm!("", clobber_abi("C", "foo")); + | ^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + +error: `C` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:15:35 + | +LL | asm!("", clobber_abi("C", "C")); + | --- ^^^ + | | + | previously specified here + +error: `win64` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:18:39 + | +LL | asm!("", clobber_abi("win64", "efiapi")); + | ------- ^^^^^^^^ + | | + | previously specified here + | + = note: these ABIs are equivalent on the current target + +error: invalid ABI for `clobber_abi` + --> $DIR/bad-clobber-abi.rs:20:35 + | +LL | asm!("", clobber_abi("C", "foo", "C")); + | ^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + +error: `C` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:20:42 + | +LL | asm!("", clobber_abi("C", "foo", "C")); + | --- ^^^ + | | + | previously specified here + +error: invalid ABI for `clobber_abi` + --> $DIR/bad-clobber-abi.rs:23:39 + | +LL | asm!("", clobber_abi("win64", "foo", "efiapi")); + | ^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + +error: `win64` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:23:46 + | +LL | asm!("", clobber_abi("win64", "foo", "efiapi")); + | ------- ^^^^^^^^ + | | + | previously specified here + | + = note: these ABIs are equivalent on the current target + +error: `C` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:26:36 + | +LL | asm!("", clobber_abi("C"), clobber_abi("C")); + | ---------------- ^^^^^^^^^^^^^^^^ + | | + | previously specified here + +error: `win64` ABI specified multiple times + --> $DIR/bad-clobber-abi.rs:29:40 + | +LL | asm!("", clobber_abi("win64"), clobber_abi("efiapi")); + | -------------------- ^^^^^^^^^^^^^^^^^^^^^ + | | + | previously specified here + | + = note: these ABIs are equivalent on the current target + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/asm/x86_64/bad-options.rs b/src/test/ui/asm/x86_64/bad-options.rs new file mode 100644 index 000000000..f7c2cd6c5 --- /dev/null +++ b/src/test/ui/asm/x86_64/bad-options.rs @@ -0,0 +1,42 @@ +// only-x86_64 + +use std::arch::{asm, global_asm}; + +fn main() { + let mut foo = 0; + unsafe { + asm!("", options(nomem, readonly)); + //~^ ERROR the `nomem` and `readonly` options are mutually exclusive + asm!("", options(pure, nomem, noreturn)); + //~^ ERROR the `pure` and `noreturn` options are mutually exclusive + //~^^ ERROR asm with the `pure` option must have at least one output + asm!("{}", in(reg) foo, options(pure, nomem)); + //~^ ERROR asm with the `pure` option must have at least one output + asm!("{}", out(reg) foo, options(noreturn)); + //~^ ERROR asm outputs are not allowed with the `noreturn` option + } + + unsafe { + asm!("", clobber_abi("foo")); + //~^ ERROR invalid ABI for `clobber_abi` + asm!("{}", out(reg) foo, clobber_abi("C")); + //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs + asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); + //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs + //~| ERROR `C` ABI specified multiple times + asm!("", out("eax") foo, clobber_abi("C")); + } +} + +global_asm!("", options(nomem)); +//~^ ERROR expected one of +global_asm!("", options(readonly)); +//~^ ERROR expected one of +global_asm!("", options(noreturn)); +//~^ ERROR expected one of +global_asm!("", options(pure)); +//~^ ERROR expected one of +global_asm!("", options(nostack)); +//~^ ERROR expected one of +global_asm!("", options(preserves_flags)); +//~^ ERROR expected one of diff --git a/src/test/ui/asm/x86_64/bad-options.stderr b/src/test/ui/asm/x86_64/bad-options.stderr new file mode 100644 index 000000000..e2351840e --- /dev/null +++ b/src/test/ui/asm/x86_64/bad-options.stderr @@ -0,0 +1,101 @@ +error: the `nomem` and `readonly` options are mutually exclusive + --> $DIR/bad-options.rs:8:18 + | +LL | asm!("", options(nomem, readonly)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the `pure` and `noreturn` options are mutually exclusive + --> $DIR/bad-options.rs:10:18 + | +LL | asm!("", options(pure, nomem, noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: asm with the `pure` option must have at least one output + --> $DIR/bad-options.rs:10:18 + | +LL | asm!("", options(pure, nomem, noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: asm with the `pure` option must have at least one output + --> $DIR/bad-options.rs:13:33 + | +LL | asm!("{}", in(reg) foo, options(pure, nomem)); + | ^^^^^^^^^^^^^^^^^^^^ + +error: asm outputs are not allowed with the `noreturn` option + --> $DIR/bad-options.rs:15:20 + | +LL | asm!("{}", out(reg) foo, options(noreturn)); + | ^^^^^^^^^^^^ + +error: asm with `clobber_abi` must specify explicit registers for outputs + --> $DIR/bad-options.rs:22:20 + | +LL | asm!("{}", out(reg) foo, clobber_abi("C")); + | ^^^^^^^^^^^^ ---------------- clobber_abi + | | + | generic outputs + +error: asm with `clobber_abi` must specify explicit registers for outputs + --> $DIR/bad-options.rs:24:20 + | +LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); + | ^^^^^^^^^^^^ ---------------- ---------------- clobber_abi + | | | + | | clobber_abi + | generic outputs + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/bad-options.rs:31:25 + | +LL | global_asm!("", options(nomem)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `readonly` + --> $DIR/bad-options.rs:33:25 + | +LL | global_asm!("", options(readonly)); + | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn` + --> $DIR/bad-options.rs:35:25 + | +LL | global_asm!("", options(noreturn)); + | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `pure` + --> $DIR/bad-options.rs:37:25 + | +LL | global_asm!("", options(pure)); + | ^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nostack` + --> $DIR/bad-options.rs:39:25 + | +LL | global_asm!("", options(nostack)); + | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags` + --> $DIR/bad-options.rs:41:25 + | +LL | global_asm!("", options(preserves_flags)); + | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: invalid ABI for `clobber_abi` + --> $DIR/bad-options.rs:20:18 + | +LL | asm!("", clobber_abi("foo")); + | ^^^^^^^^^^^^^^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64` + +error: `C` ABI specified multiple times + --> $DIR/bad-options.rs:24:52 + | +LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); + | ---------------- ^^^^^^^^^^^^^^^^ + | | + | previously specified here + +error: aborting due to 15 previous errors + diff --git a/src/test/ui/asm/x86_64/bad-reg.rs b/src/test/ui/asm/x86_64/bad-reg.rs new file mode 100644 index 000000000..a4f50a534 --- /dev/null +++ b/src/test/ui/asm/x86_64/bad-reg.rs @@ -0,0 +1,72 @@ +// only-x86_64 +// compile-flags: -C target-feature=+avx2 + +#![feature(asm_const, asm_sym)] + +use std::arch::asm; + +fn main() { + let mut foo = 0; + let mut bar = 0; + unsafe { + // Bad register/register class + + asm!("{}", in(foo) foo); + //~^ ERROR invalid register class `foo`: unknown register class + asm!("", in("foo") foo); + //~^ ERROR invalid register `foo`: unknown register + asm!("{:z}", in(reg) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:r}", in(xmm_reg) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:a}", const 0); + //~^ ERROR asm template modifiers are not allowed for `const` arguments + asm!("{:a}", sym main); + //~^ ERROR asm template modifiers are not allowed for `sym` arguments + asm!("", in("ebp") foo); + //~^ ERROR invalid register `ebp`: the frame pointer cannot be used as an operand + asm!("", in("rsp") foo); + //~^ ERROR invalid register `rsp`: the stack pointer cannot be used as an operand + asm!("", in("ip") foo); + //~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand + + asm!("", in("st(2)") foo); + //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output + //~| ERROR `i32` cannot be used with this register class + asm!("", in("mm0") foo); + //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output + //~| ERROR `i32` cannot be used with this register class + asm!("", in("k0") foo); + //~^ ERROR register class `kreg0` can only be used as a clobber, not as an input or output + //~| ERROR `i32` cannot be used with this register class + asm!("", out("st(2)") _); + asm!("", out("mm0") _); + asm!("{}", in(x87_reg) foo); + //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output + //~| ERROR `i32` cannot be used with this register class + asm!("{}", in(mmx_reg) foo); + //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output + //~| ERROR `i32` cannot be used with this register class + asm!("{}", out(x87_reg) _); + //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output + asm!("{}", out(mmx_reg) _); + //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output + + // Explicit register conflicts + // (except in/lateout which don't conflict) + + asm!("", in("eax") foo, in("al") bar); + //~^ ERROR register `al` conflicts with register `ax` + //~| ERROR `i32` cannot be used with this register class + asm!("", in("rax") foo, out("rax") bar); + //~^ ERROR register `ax` conflicts with register `ax` + asm!("", in("al") foo, lateout("al") bar); + //~^ ERROR `i32` cannot be used with this register class + //~| ERROR `i32` cannot be used with this register class + asm!("", in("xmm0") foo, in("ymm0") bar); + //~^ ERROR register `ymm0` conflicts with register `xmm0` + asm!("", in("xmm0") foo, out("ymm0") bar); + //~^ ERROR register `ymm0` conflicts with register `xmm0` + asm!("", in("xmm0") foo, lateout("ymm0") bar); + } +} diff --git a/src/test/ui/asm/x86_64/bad-reg.stderr b/src/test/ui/asm/x86_64/bad-reg.stderr new file mode 100644 index 000000000..82b7ebd0f --- /dev/null +++ b/src/test/ui/asm/x86_64/bad-reg.stderr @@ -0,0 +1,218 @@ +error: invalid register class `foo`: unknown register class + --> $DIR/bad-reg.rs:14:20 + | +LL | asm!("{}", in(foo) foo); + | ^^^^^^^^^^^ + +error: invalid register `foo`: unknown register + --> $DIR/bad-reg.rs:16:18 + | +LL | asm!("", in("foo") foo); + | ^^^^^^^^^^^^^ + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:18:15 + | +LL | asm!("{:z}", in(reg) foo); + | ^^^^ ----------- argument + | | + | template modifier + | + = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, `r` + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:20:15 + | +LL | asm!("{:r}", in(xmm_reg) foo); + | ^^^^ --------------- argument + | | + | template modifier + | + = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, `z` + +error: asm template modifiers are not allowed for `const` arguments + --> $DIR/bad-reg.rs:22:15 + | +LL | asm!("{:a}", const 0); + | ^^^^ ------- argument + | | + | template modifier + +error: asm template modifiers are not allowed for `sym` arguments + --> $DIR/bad-reg.rs:24:15 + | +LL | asm!("{:a}", sym main); + | ^^^^ -------- argument + | | + | template modifier + +error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:26:18 + | +LL | asm!("", in("ebp") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:28:18 + | +LL | asm!("", in("rsp") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:30:18 + | +LL | asm!("", in("ip") foo); + | ^^^^^^^^^^^^ + +error: register class `x87_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:33:18 + | +LL | asm!("", in("st(2)") foo); + | ^^^^^^^^^^^^^^^ + +error: register class `mmx_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:36:18 + | +LL | asm!("", in("mm0") foo); + | ^^^^^^^^^^^^^ + +error: register class `kreg0` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:39:18 + | +LL | asm!("", in("k0") foo); + | ^^^^^^^^^^^^ + +error: register class `x87_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:44:20 + | +LL | asm!("{}", in(x87_reg) foo); + | ^^^^^^^^^^^^^^^ + +error: register class `mmx_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:47:20 + | +LL | asm!("{}", in(mmx_reg) foo); + | ^^^^^^^^^^^^^^^ + +error: register class `x87_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:50:20 + | +LL | asm!("{}", out(x87_reg) _); + | ^^^^^^^^^^^^^^ + +error: register class `mmx_reg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:52:20 + | +LL | asm!("{}", out(mmx_reg) _); + | ^^^^^^^^^^^^^^ + +error: register `al` conflicts with register `ax` + --> $DIR/bad-reg.rs:58:33 + | +LL | asm!("", in("eax") foo, in("al") bar); + | ------------- ^^^^^^^^^^^^ register `al` + | | + | register `ax` + +error: register `ax` conflicts with register `ax` + --> $DIR/bad-reg.rs:61:33 + | +LL | asm!("", in("rax") foo, out("rax") bar); + | ------------- ^^^^^^^^^^^^^^ register `ax` + | | + | register `ax` + | +help: use `lateout` instead of `out` to avoid conflict + --> $DIR/bad-reg.rs:61:18 + | +LL | asm!("", in("rax") foo, out("rax") bar); + | ^^^^^^^^^^^^^ + +error: register `ymm0` conflicts with register `xmm0` + --> $DIR/bad-reg.rs:66:34 + | +LL | asm!("", in("xmm0") foo, in("ymm0") bar); + | -------------- ^^^^^^^^^^^^^^ register `ymm0` + | | + | register `xmm0` + +error: register `ymm0` conflicts with register `xmm0` + --> $DIR/bad-reg.rs:68:34 + | +LL | asm!("", in("xmm0") foo, out("ymm0") bar); + | -------------- ^^^^^^^^^^^^^^^ register `ymm0` + | | + | register `xmm0` + | +help: use `lateout` instead of `out` to avoid conflict + --> $DIR/bad-reg.rs:68:18 + | +LL | asm!("", in("xmm0") foo, out("ymm0") bar); + | ^^^^^^^^^^^^^^ + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:33:30 + | +LL | asm!("", in("st(2)") foo); + | ^^^ + | + = note: register class `x87_reg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:36:28 + | +LL | asm!("", in("mm0") foo); + | ^^^ + | + = note: register class `mmx_reg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:39:27 + | +LL | asm!("", in("k0") foo); + | ^^^ + | + = note: register class `kreg0` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:44:32 + | +LL | asm!("{}", in(x87_reg) foo); + | ^^^ + | + = note: register class `x87_reg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:47:32 + | +LL | asm!("{}", in(mmx_reg) foo); + | ^^^ + | + = note: register class `mmx_reg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:58:42 + | +LL | asm!("", in("eax") foo, in("al") bar); + | ^^^ + | + = note: register class `reg_byte` supports these types: i8 + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:63:27 + | +LL | asm!("", in("al") foo, lateout("al") bar); + | ^^^ + | + = note: register class `reg_byte` supports these types: i8 + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:63:46 + | +LL | asm!("", in("al") foo, lateout("al") bar); + | ^^^ + | + = note: register class `reg_byte` supports these types: i8 + +error: aborting due to 28 previous errors + diff --git a/src/test/ui/asm/x86_64/const.rs b/src/test/ui/asm/x86_64/const.rs new file mode 100644 index 000000000..d523ae021 --- /dev/null +++ b/src/test/ui/asm/x86_64/const.rs @@ -0,0 +1,44 @@ +// only-x86_64 +// run-pass +// needs-asm-support +// revisions: mirunsafeck thirunsafeck +// [thirunsafeck]compile-flags: -Z thir-unsafeck + +#![feature(asm_const)] + +use std::arch::{asm, global_asm}; + +fn const_generic<const X: usize>() -> usize { + unsafe { + let a: usize; + asm!("mov {}, {}", out(reg) a, const X); + a + } +} + +const fn constfn(x: usize) -> usize { + x +} + +fn main() { + unsafe { + let a: usize; + asm!("mov {}, {}", out(reg) a, const 5); + assert_eq!(a, 5); + + let b: usize; + asm!("mov {}, {}", out(reg) b, const constfn(5)); + assert_eq!(b, 5); + + let c: usize; + asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5)); + assert_eq!(c, 10); + } + + let d = const_generic::<5>(); + assert_eq!(d, 5); +} + +global_asm!("mov eax, {}", const 5); +global_asm!("mov eax, {}", const constfn(5)); +global_asm!("mov eax, {}", const constfn(5) + constfn(5)); diff --git a/src/test/ui/asm/x86_64/duplicate-options.fixed b/src/test/ui/asm/x86_64/duplicate-options.fixed new file mode 100644 index 000000000..c5f14f5f7 --- /dev/null +++ b/src/test/ui/asm/x86_64/duplicate-options.fixed @@ -0,0 +1,29 @@ +// only-x86_64 +// run-rustfix + +use std::arch::{asm, global_asm}; + +fn main() { + unsafe { + asm!("", options(nomem, )); + //~^ ERROR the `nomem` option was already provided + asm!("", options(att_syntax, )); + //~^ ERROR the `att_syntax` option was already provided + asm!("", options(nostack, att_syntax), options()); + //~^ ERROR the `nostack` option was already provided + asm!("", options(nostack, ), options(), options()); + //~^ ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + asm!( + "", + options(nomem, noreturn), + options(att_syntax, ), //~ ERROR the `noreturn` option was already provided + options( nostack), //~ ERROR the `nomem` option was already provided + options(), //~ ERROR the `noreturn` option was already provided + ); + } +} + +global_asm!("", options(att_syntax, )); +//~^ ERROR the `att_syntax` option was already provided diff --git a/src/test/ui/asm/x86_64/duplicate-options.rs b/src/test/ui/asm/x86_64/duplicate-options.rs new file mode 100644 index 000000000..a8dce1f8d --- /dev/null +++ b/src/test/ui/asm/x86_64/duplicate-options.rs @@ -0,0 +1,29 @@ +// only-x86_64 +// run-rustfix + +use std::arch::{asm, global_asm}; + +fn main() { + unsafe { + asm!("", options(nomem, nomem)); + //~^ ERROR the `nomem` option was already provided + asm!("", options(att_syntax, att_syntax)); + //~^ ERROR the `att_syntax` option was already provided + asm!("", options(nostack, att_syntax), options(nostack)); + //~^ ERROR the `nostack` option was already provided + asm!("", options(nostack, nostack), options(nostack), options(nostack)); + //~^ ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + asm!( + "", + options(nomem, noreturn), + options(att_syntax, noreturn), //~ ERROR the `noreturn` option was already provided + options(nomem, nostack), //~ ERROR the `nomem` option was already provided + options(noreturn), //~ ERROR the `noreturn` option was already provided + ); + } +} + +global_asm!("", options(att_syntax, att_syntax)); +//~^ ERROR the `att_syntax` option was already provided diff --git a/src/test/ui/asm/x86_64/duplicate-options.stderr b/src/test/ui/asm/x86_64/duplicate-options.stderr new file mode 100644 index 000000000..53edf8fb9 --- /dev/null +++ b/src/test/ui/asm/x86_64/duplicate-options.stderr @@ -0,0 +1,62 @@ +error: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:8:33 + | +LL | asm!("", options(nomem, nomem)); + | ^^^^^ this option was already provided + +error: the `att_syntax` option was already provided + --> $DIR/duplicate-options.rs:10:38 + | +LL | asm!("", options(att_syntax, att_syntax)); + | ^^^^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:12:56 + | +LL | asm!("", options(nostack, att_syntax), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:35 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:53 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:71 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `noreturn` option was already provided + --> $DIR/duplicate-options.rs:21:33 + | +LL | options(att_syntax, noreturn), + | ^^^^^^^^ this option was already provided + +error: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:22:21 + | +LL | options(nomem, nostack), + | ^^^^^ this option was already provided + +error: the `noreturn` option was already provided + --> $DIR/duplicate-options.rs:23:21 + | +LL | options(noreturn), + | ^^^^^^^^ this option was already provided + +error: the `att_syntax` option was already provided + --> $DIR/duplicate-options.rs:28:37 + | +LL | global_asm!("", options(att_syntax, att_syntax)); + | ^^^^^^^^^^ this option was already provided + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/asm/x86_64/interpolated-idents.rs b/src/test/ui/asm/x86_64/interpolated-idents.rs new file mode 100644 index 000000000..c05633ae8 --- /dev/null +++ b/src/test/ui/asm/x86_64/interpolated-idents.rs @@ -0,0 +1,24 @@ +// only-x86_64 + +use std::arch::asm; + +macro_rules! m { + ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident + $pure:ident $nomem:ident $readonly:ident $preserves_flags:ident + $noreturn:ident $nostack:ident $att_syntax:ident $options:ident) => { + unsafe { + asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x, + //~^ ERROR asm outputs are not allowed with the `noreturn` option + const x, sym x, + $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax)); + //~^ ERROR the `nomem` and `readonly` options are mutually exclusive + //~| ERROR the `pure` and `noreturn` options are mutually exclusive + } + }; +} + +fn main() { + m!(in out lateout inout inlateout const sym + pure nomem readonly preserves_flags + noreturn nostack att_syntax options); +} diff --git a/src/test/ui/asm/x86_64/interpolated-idents.stderr b/src/test/ui/asm/x86_64/interpolated-idents.stderr new file mode 100644 index 000000000..6ac2ac5a7 --- /dev/null +++ b/src/test/ui/asm/x86_64/interpolated-idents.stderr @@ -0,0 +1,51 @@ +error: the `nomem` and `readonly` options are mutually exclusive + --> $DIR/interpolated-idents.rs:13:13 + | +LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / m!(in out lateout inout inlateout const sym +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack att_syntax options); + | |___________________________________________- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: the `pure` and `noreturn` options are mutually exclusive + --> $DIR/interpolated-idents.rs:13:13 + | +LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / m!(in out lateout inout inlateout const sym +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack att_syntax options); + | |___________________________________________- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm outputs are not allowed with the `noreturn` option + --> $DIR/interpolated-idents.rs:10:32 + | +LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x, + | ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^ +... +LL | m!(in out lateout inout inlateout const sym + | _____- + | |_____| + | |_____| + | |_____| + | | +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack att_syntax options); + | | - + | |___________________________________________| + | |___________________________________________in this macro invocation + | |___________________________________________in this macro invocation + | |___________________________________________in this macro invocation + | in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/asm/x86_64/issue-82869.rs b/src/test/ui/asm/x86_64/issue-82869.rs new file mode 100644 index 000000000..67933666e --- /dev/null +++ b/src/test/ui/asm/x86_64/issue-82869.rs @@ -0,0 +1,25 @@ +// needs-asm-support +// only-x86_64 +// Make sure rustc doesn't ICE on asm! for a foreign architecture. + +#![crate_type = "rlib"] + +use std::arch::asm; + +pub unsafe fn aarch64(a: f64, b: f64) -> f64 { + let c; + asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { + || {}; + b + }); + //~^^^^ invalid register class + //~^^^^^ invalid register class + //~^^^^^^ invalid register + c +} + +pub unsafe fn x86(a: f64, b: f64) -> f64 { + let c; + asm!("addsd {}, {}, xmm0", out(xmm_reg) c, in(xmm_reg) a, in("xmm0") b); + c +} diff --git a/src/test/ui/asm/x86_64/issue-82869.stderr b/src/test/ui/asm/x86_64/issue-82869.stderr new file mode 100644 index 000000000..3cf9d6d1c --- /dev/null +++ b/src/test/ui/asm/x86_64/issue-82869.stderr @@ -0,0 +1,24 @@ +error: invalid register class `vreg`: unknown register class + --> $DIR/issue-82869.rs:11:32 + | +LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { + | ^^^^^^^^^^^ + +error: invalid register class `vreg`: unknown register class + --> $DIR/issue-82869.rs:11:45 + | +LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { + | ^^^^^^^^^^ + +error: invalid register `d0`: unknown register + --> $DIR/issue-82869.rs:11:57 + | +LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") { + | _________________________________________________________^ +LL | | || {}; +LL | | b +LL | | }); + | |_____^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/asm/x86_64/issue-89875.rs b/src/test/ui/asm/x86_64/issue-89875.rs new file mode 100644 index 000000000..669fd7e7e --- /dev/null +++ b/src/test/ui/asm/x86_64/issue-89875.rs @@ -0,0 +1,17 @@ +// build-pass +// needs-asm-support +// only-x86_64 + +#![feature(target_feature_11)] + +use std::arch::asm; + +#[target_feature(enable = "avx")] +fn main() { + unsafe { + asm!( + "/* {} */", + out(ymm_reg) _, + ); + } +} diff --git a/src/test/ui/asm/x86_64/issue-96797.rs b/src/test/ui/asm/x86_64/issue-96797.rs new file mode 100644 index 000000000..d3e0906f3 --- /dev/null +++ b/src/test/ui/asm/x86_64/issue-96797.rs @@ -0,0 +1,26 @@ +// build-pass +// compile-flags: -O +// min-llvm-version: 14.0.5 +// needs-asm-support +// only-x86_64 +// only-linux + +// regression test for #96797 + +#![feature(asm_sym)] + +use std::arch::global_asm; + +#[no_mangle] +fn my_func() {} + +global_asm!("call_foobar: jmp {}", sym foobar); + +fn foobar() {} + +fn main() { + extern "Rust" { + fn call_foobar(); + } + unsafe { call_foobar() }; +} diff --git a/src/test/ui/asm/x86_64/may_unwind.rs b/src/test/ui/asm/x86_64/may_unwind.rs new file mode 100644 index 000000000..9844d63f0 --- /dev/null +++ b/src/test/ui/asm/x86_64/may_unwind.rs @@ -0,0 +1,38 @@ +// min-llvm-version: 13.0.0 +// only-x86_64 +// run-pass +// needs-asm-support + +#![feature(asm_sym, asm_unwind)] + +use std::arch::asm; +use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; + +struct Foo<'a>(&'a mut bool); + +impl Drop for Foo<'_> { + fn drop(&mut self) { + *self.0 = false; + } +} + +extern "C" fn panicky() { + resume_unwind(Box::new(())); +} + +fn main() { + let flag = &mut true; + catch_unwind(AssertUnwindSafe(|| { + let _foo = Foo(flag); + unsafe { + asm!( + "call {}", + sym panicky, + clobber_abi("C"), + options(may_unwind) + ); + } + })) + .expect_err("expected a panic"); + assert_eq!(*flag, false); +} diff --git a/src/test/ui/asm/x86_64/multiple-clobber-abi.rs b/src/test/ui/asm/x86_64/multiple-clobber-abi.rs new file mode 100644 index 000000000..513eb270e --- /dev/null +++ b/src/test/ui/asm/x86_64/multiple-clobber-abi.rs @@ -0,0 +1,35 @@ +// run-pass +// needs-asm-support +// only-x86_64 + +// Checks that multiple clobber_abi options can be used + +#![feature(asm_sym)] + +use std::arch::asm; + +extern "sysv64" fn foo(x: i32) -> i32 { + x + 16 +} + +extern "win64" fn bar(x: i32) -> i32 { + x / 2 +} + +fn main() { + let x = 8; + let y: i32; + // call `foo` with `x` as the input, and then `bar` with the output of `foo` + // and output that to `y` + unsafe { + asm!( + "call {}; mov rcx, rax; call {}", + sym foo, + sym bar, + in("rdi") x, + out("rax") y, + clobber_abi("sysv64", "win64"), + ); + } + assert_eq!((x, y), (8, 12)); +} diff --git a/src/test/ui/asm/x86_64/parse-error.rs b/src/test/ui/asm/x86_64/parse-error.rs new file mode 100644 index 000000000..9aeb6b285 --- /dev/null +++ b/src/test/ui/asm/x86_64/parse-error.rs @@ -0,0 +1,137 @@ +// only-x86_64 + +#![feature(asm_const)] + +use std::arch::{asm, global_asm}; + +fn main() { + let mut foo = 0; + let mut bar = 0; + unsafe { + asm!(); + //~^ ERROR requires at least a template string argument + asm!(foo); + //~^ ERROR asm template must be a string literal + asm!("{}" foo); + //~^ ERROR expected token: `,` + asm!("{}", foo); + //~^ ERROR expected operand, clobber_abi, options, or additional template string + asm!("{}", in foo); + //~^ ERROR expected `(`, found `foo` + asm!("{}", in(reg foo)); + //~^ ERROR expected `)`, found `foo` + asm!("{}", in(reg)); + //~^ ERROR expected expression, found end of macro arguments + asm!("{}", inout(=) foo => bar); + //~^ ERROR expected register class or explicit register + asm!("{}", inout(reg) foo =>); + //~^ ERROR expected expression, found end of macro arguments + asm!("{}", in(reg) foo => bar); + //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` + asm!("{}", sym foo + bar); + //~^ ERROR expected a path for argument to `sym` + asm!("", options(foo)); + //~^ ERROR expected one of + asm!("", options(nomem foo)); + //~^ ERROR expected one of + asm!("", options(nomem, foo)); + //~^ ERROR expected one of + asm!("{}", options(), const foo); + //~^ ERROR arguments are not allowed after options + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", clobber_abi()); + //~^ ERROR at least one abi must be provided + asm!("", clobber_abi(foo)); + //~^ ERROR expected string literal + asm!("", clobber_abi("C" foo)); + //~^ ERROR expected one of `)` or `,`, found `foo` + asm!("", clobber_abi("C", foo)); + //~^ ERROR expected string literal + asm!("{}", clobber_abi("C"), const foo); + //~^ ERROR arguments are not allowed after clobber_abi + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", options(), clobber_abi("C")); + //~^ ERROR clobber_abi is not allowed after options + asm!("{}", options(), clobber_abi("C"), const foo); + //~^ ERROR clobber_abi is not allowed after options + asm!("{a}", a = const foo, a = const bar); + //~^ ERROR duplicate argument named `a` + //~^^ ERROR argument never used + //~^^^ ERROR attempt to use a non-constant value in a constant + //~^^^^ ERROR attempt to use a non-constant value in a constant + asm!("", a = in("eax") foo); + //~^ ERROR explicit register arguments cannot have names + asm!("{a}", in("eax") foo, a = const bar); + //~^ ERROR named arguments cannot follow explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("{a}", in("eax") foo, a = const bar); + //~^ ERROR named arguments cannot follow explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("{1}", in("eax") foo, const bar); + //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + 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 + asm!("{}", in(reg) _); + //~^ ERROR _ cannot be used for input operands + asm!("{}", inout(reg) _); + //~^ ERROR _ cannot be used for input operands + asm!("{}", inlateout(reg) _); + //~^ ERROR _ cannot be used for input operands + } +} + +const FOO: i32 = 1; +const BAR: i32 = 2; +global_asm!(); +//~^ ERROR requires at least a template string argument +global_asm!(FOO); +//~^ ERROR asm template must be a string literal +global_asm!("{}" FOO); +//~^ ERROR expected token: `,` +global_asm!("{}", FOO); +//~^ ERROR expected operand, options, or additional template string +global_asm!("{}", const); +//~^ ERROR expected expression, found end of macro arguments +global_asm!("{}", const(reg) FOO); +//~^ ERROR expected one of +global_asm!("", options(FOO)); +//~^ ERROR expected one of +global_asm!("", options(nomem FOO)); +//~^ ERROR expected one of +global_asm!("", options(nomem, FOO)); +//~^ ERROR expected one of +global_asm!("{}", options(), const FOO); +//~^ ERROR arguments are not allowed after options +global_asm!("", clobber_abi(FOO)); +//~^ ERROR expected string literal +global_asm!("", clobber_abi("C" FOO)); +//~^ ERROR expected one of `)` or `,`, found `FOO` +global_asm!("", clobber_abi("C", FOO)); +//~^ ERROR expected string literal +global_asm!("{}", clobber_abi("C"), const FOO); +//~^ ERROR arguments are not allowed after clobber_abi +//~^^ ERROR `clobber_abi` cannot be used with `global_asm!` +global_asm!("", options(), clobber_abi("C")); +//~^ ERROR clobber_abi is not allowed after options +global_asm!("{}", options(), clobber_abi("C"), const FOO); +//~^ ERROR clobber_abi is not allowed after options +global_asm!("", clobber_abi("C"), clobber_abi("C")); +//~^ ERROR `clobber_abi` cannot be used with `global_asm!` +global_asm!("{a}", a = const FOO, a = const BAR); +//~^ ERROR duplicate argument named `a` +//~^^ ERROR argument never used +global_asm!("", options(), ""); +//~^ ERROR expected one of +global_asm!("{}", const FOO, "{}", const FOO); +//~^ ERROR expected one of +global_asm!(format!("{{{}}}", 0), const FOO); +//~^ ERROR asm template must be a string literal +global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); +//~^ ERROR asm template must be a string literal diff --git a/src/test/ui/asm/x86_64/parse-error.stderr b/src/test/ui/asm/x86_64/parse-error.stderr new file mode 100644 index 000000000..57702c37b --- /dev/null +++ b/src/test/ui/asm/x86_64/parse-error.stderr @@ -0,0 +1,458 @@ +error: requires at least a template string argument + --> $DIR/parse-error.rs:11:9 + | +LL | asm!(); + | ^^^^^^ + +error: asm template must be a string literal + --> $DIR/parse-error.rs:13:14 + | +LL | asm!(foo); + | ^^^ + +error: expected token: `,` + --> $DIR/parse-error.rs:15:19 + | +LL | asm!("{}" foo); + | ^^^ expected `,` + +error: expected operand, clobber_abi, options, or additional template string + --> $DIR/parse-error.rs:17:20 + | +LL | asm!("{}", foo); + | ^^^ expected operand, clobber_abi, options, or additional template string + +error: expected `(`, found `foo` + --> $DIR/parse-error.rs:19:23 + | +LL | asm!("{}", in foo); + | ^^^ expected `(` + +error: expected `)`, found `foo` + --> $DIR/parse-error.rs:21:27 + | +LL | asm!("{}", in(reg foo)); + | ^^^ expected `)` + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:23:27 + | +LL | asm!("{}", in(reg)); + | ^ expected expression + +error: expected register class or explicit register + --> $DIR/parse-error.rs:25:26 + | +LL | asm!("{}", inout(=) foo => bar); + | ^ + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:27:37 + | +LL | asm!("{}", inout(reg) foo =>); + | ^ expected expression + +error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` + --> $DIR/parse-error.rs:29:32 + | +LL | asm!("{}", in(reg) foo => bar); + | ^^ expected one of 7 possible tokens + +error: expected a path for argument to `sym` + --> $DIR/parse-error.rs:31:24 + | +LL | asm!("{}", sym foo + bar); + | ^^^^^^^^^ + +error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo` + --> $DIR/parse-error.rs:33:26 + | +LL | asm!("", options(foo)); + | ^^^ expected one of 10 possible tokens + +error: expected one of `)` or `,`, found `foo` + --> $DIR/parse-error.rs:35:32 + | +LL | asm!("", options(nomem foo)); + | ^^^ expected one of `)` or `,` + +error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo` + --> $DIR/parse-error.rs:37:33 + | +LL | asm!("", options(nomem, foo)); + | ^^^ expected one of 10 possible tokens + +error: arguments are not allowed after options + --> $DIR/parse-error.rs:39:31 + | +LL | asm!("{}", options(), const foo); + | --------- ^^^^^^^^^ argument + | | + | previous options + +error: at least one abi must be provided as an argument to `clobber_abi` + --> $DIR/parse-error.rs:42:30 + | +LL | asm!("", clobber_abi()); + | ^ + +error: expected string literal + --> $DIR/parse-error.rs:44:30 + | +LL | asm!("", clobber_abi(foo)); + | ^^^ not a string literal + +error: expected one of `)` or `,`, found `foo` + --> $DIR/parse-error.rs:46:34 + | +LL | asm!("", clobber_abi("C" foo)); + | ^^^ expected one of `)` or `,` + +error: expected string literal + --> $DIR/parse-error.rs:48:35 + | +LL | asm!("", clobber_abi("C", foo)); + | ^^^ not a string literal + +error: arguments are not allowed after clobber_abi + --> $DIR/parse-error.rs:50:38 + | +LL | asm!("{}", clobber_abi("C"), const foo); + | ---------------- ^^^^^^^^^ argument + | | + | clobber_abi + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:53:29 + | +LL | asm!("", options(), clobber_abi("C")); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:55:31 + | +LL | asm!("{}", options(), clobber_abi("C"), const foo); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: duplicate argument named `a` + --> $DIR/parse-error.rs:57:36 + | +LL | asm!("{a}", a = const foo, a = const bar); + | ------------- ^^^^^^^^^^^^^ duplicate argument + | | + | previously here + +error: argument never used + --> $DIR/parse-error.rs:57:36 + | +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` + +error: explicit register arguments cannot have names + --> $DIR/parse-error.rs:62:18 + | +LL | asm!("", a = in("eax") foo); + | ^^^^^^^^^^^^^^^^^ + +error: named arguments cannot follow explicit register arguments + --> $DIR/parse-error.rs:64:36 + | +LL | asm!("{a}", in("eax") foo, a = const bar); + | ------------- ^^^^^^^^^^^^^ named argument + | | + | explicit register argument + +error: named arguments cannot follow explicit register arguments + --> $DIR/parse-error.rs:67:36 + | +LL | asm!("{a}", in("eax") foo, a = const bar); + | ------------- ^^^^^^^^^^^^^ named argument + | | + | explicit register argument + +error: positional arguments cannot follow named arguments or explicit register arguments + --> $DIR/parse-error.rs:70:36 + | +LL | asm!("{1}", in("eax") foo, const bar); + | ------------- ^^^^^^^^^ positional argument + | | + | explicit register argument + +error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` + --> $DIR/parse-error.rs:73:29 + | +LL | asm!("", options(), ""); + | ^^ expected one of 9 possible tokens + +error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` + --> $DIR/parse-error.rs:75:33 + | +LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); + | ^^^^ expected one of 9 possible tokens + +error: asm template must be a string literal + --> $DIR/parse-error.rs:77:14 + | +LL | asm!(format!("{{{}}}", 0), in(reg) foo); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm template must be a string literal + --> $DIR/parse-error.rs:79:21 + | +LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:81:28 + | +LL | asm!("{}", in(reg) _); + | ^ + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:83:31 + | +LL | asm!("{}", inout(reg) _); + | ^ + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:85:35 + | +LL | asm!("{}", inlateout(reg) _); + | ^ + +error: requires at least a template string argument + --> $DIR/parse-error.rs:92:1 + | +LL | global_asm!(); + | ^^^^^^^^^^^^^ + +error: asm template must be a string literal + --> $DIR/parse-error.rs:94:13 + | +LL | global_asm!(FOO); + | ^^^ + +error: expected token: `,` + --> $DIR/parse-error.rs:96:18 + | +LL | global_asm!("{}" FOO); + | ^^^ expected `,` + +error: expected operand, options, or additional template string + --> $DIR/parse-error.rs:98:19 + | +LL | global_asm!("{}", FOO); + | ^^^ expected operand, options, or additional template string + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:100:24 + | +LL | global_asm!("{}", const); + | ^ expected expression + +error: expected one of `,`, `.`, `?`, or an operator, found `FOO` + --> $DIR/parse-error.rs:102:30 + | +LL | global_asm!("{}", const(reg) FOO); + | ^^^ expected one of `,`, `.`, `?`, or an operator + +error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` + --> $DIR/parse-error.rs:104:25 + | +LL | global_asm!("", options(FOO)); + | ^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/parse-error.rs:106:25 + | +LL | global_asm!("", options(nomem FOO)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/parse-error.rs:108:25 + | +LL | global_asm!("", options(nomem, FOO)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: arguments are not allowed after options + --> $DIR/parse-error.rs:110:30 + | +LL | global_asm!("{}", options(), const FOO); + | --------- ^^^^^^^^^ argument + | | + | previous options + +error: expected string literal + --> $DIR/parse-error.rs:112:29 + | +LL | global_asm!("", clobber_abi(FOO)); + | ^^^ not a string literal + +error: expected one of `)` or `,`, found `FOO` + --> $DIR/parse-error.rs:114:33 + | +LL | global_asm!("", clobber_abi("C" FOO)); + | ^^^ expected one of `)` or `,` + +error: expected string literal + --> $DIR/parse-error.rs:116:34 + | +LL | global_asm!("", clobber_abi("C", FOO)); + | ^^^ not a string literal + +error: arguments are not allowed after clobber_abi + --> $DIR/parse-error.rs:118:37 + | +LL | global_asm!("{}", clobber_abi("C"), const FOO); + | ---------------- ^^^^^^^^^ argument + | | + | clobber_abi + +error: `clobber_abi` cannot be used with `global_asm!` + --> $DIR/parse-error.rs:118:19 + | +LL | global_asm!("{}", clobber_abi("C"), const FOO); + | ^^^^^^^^^^^^^^^^ + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:121:28 + | +LL | global_asm!("", options(), clobber_abi("C")); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:123:30 + | +LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: `clobber_abi` cannot be used with `global_asm!` + --> $DIR/parse-error.rs:125:17 + | +LL | global_asm!("", clobber_abi("C"), clobber_abi("C")); + | ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ + +error: duplicate argument named `a` + --> $DIR/parse-error.rs:127:35 + | +LL | global_asm!("{a}", a = const FOO, a = const BAR); + | ------------- ^^^^^^^^^^^^^ duplicate argument + | | + | previously here + +error: argument never used + --> $DIR/parse-error.rs:127:35 + | +LL | global_asm!("{a}", a = const FOO, a = const BAR); + | ^^^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` + +error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""` + --> $DIR/parse-error.rs:130:28 + | +LL | global_asm!("", options(), ""); + | ^^ expected one of `clobber_abi`, `const`, `options`, or `sym` + +error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"` + --> $DIR/parse-error.rs:132:30 + | +LL | global_asm!("{}", const FOO, "{}", const FOO); + | ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym` + +error: asm template must be a string literal + --> $DIR/parse-error.rs:134:13 + | +LL | global_asm!(format!("{{{}}}", 0), const FOO); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm template must be a string literal + --> $DIR/parse-error.rs:136:20 + | +LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:39:37 + | +LL | let mut foo = 0; + | ----------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{}", options(), const foo); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:50:44 + | +LL | let mut foo = 0; + | ----------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{}", clobber_abi("C"), const foo); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:57:31 + | +LL | let mut foo = 0; + | ----------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:57:46 + | +LL | let mut bar = 0; + | ----------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:64:46 + | +LL | let mut bar = 0; + | ----------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", in("eax") foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:67:46 + | +LL | let mut bar = 0; + | ----------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", in("eax") foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:70:42 + | +LL | let mut bar = 0; + | ----------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{1}", in("eax") foo, const bar); + | ^^^ non-constant value + +error: aborting due to 66 previous errors + +For more information about this error, try `rustc --explain E0435`. diff --git a/src/test/ui/asm/x86_64/srcloc.rs b/src/test/ui/asm/x86_64/srcloc.rs new file mode 100644 index 000000000..1135ad2e1 --- /dev/null +++ b/src/test/ui/asm/x86_64/srcloc.rs @@ -0,0 +1,131 @@ +// only-x86_64 +// build-fail +// compile-flags: -Ccodegen-units=1 + +use std::arch::asm; + +// Checks that inline asm errors are mapped to the correct line in the source code. + +fn main() { + unsafe { + asm!("invalid_instruction"); + //~^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(" + invalid_instruction + "); + //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(r#" + invalid_instruction + "#); + //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(" + mov eax, eax + invalid_instruction + mov eax, eax + "); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(r#" + mov eax, eax + invalid_instruction + mov eax, eax + "#); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(concat!("invalid", "_", "instruction")); + //~^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + 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' + + asm!( + "", + "\n", + "invalid_instruction" + ); + //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + } +} diff --git a/src/test/ui/asm/x86_64/srcloc.stderr b/src/test/ui/asm/x86_64/srcloc.stderr new file mode 100644 index 000000000..8899c1b91 --- /dev/null +++ b/src/test/ui/asm/x86_64/srcloc.stderr @@ -0,0 +1,302 @@ +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:11:15 + | +LL | asm!("invalid_instruction"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:15:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> <inline asm>:3:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:20:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> <inline asm>:3:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:26:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> <inline asm>:4:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:33:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> <inline asm>:4:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:38:14 + | +LL | asm!(concat!("invalid", "_", "instruction")); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +warning: scale factor without index register is ignored + --> $DIR/srcloc.rs:41:15 + | +LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:23 + | +LL | movaps %xmm3, (%esi, 2) + | ^ + +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: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:127:14 + | +LL | "invalid_instruction" + | ^ + | +note: instantiated into assembly here + --> <inline asm>:5:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 24 previous errors; 1 warning emitted + diff --git a/src/test/ui/asm/x86_64/sym.rs b/src/test/ui/asm/x86_64/sym.rs new file mode 100644 index 000000000..622365bc7 --- /dev/null +++ b/src/test/ui/asm/x86_64/sym.rs @@ -0,0 +1,85 @@ +// min-llvm-version: 12.0.1 +// only-x86_64 +// only-linux +// needs-asm-support +// run-pass + +#![feature(thread_local, asm_sym)] + +use std::arch::asm; + +extern "C" fn f1() -> i32 { + 111 +} + +// The compiler will generate a shim to hide the caller location parameter. +#[track_caller] +fn f2() -> i32 { + 222 +} + +macro_rules! call { + ($func:path) => { + unsafe { + let result: i32; + asm!("call {}", sym $func, + out("rax") result, + out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _, + out("r8") _, out("r9") _, out("r10") _, out("r11") _, + out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _, + out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _, + out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _, + out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _, + ); + result + } + } +} + +macro_rules! static_addr { + ($s:expr) => { + unsafe { + let result: *const u32; + // LEA performs a RIP-relative address calculation and returns the address + asm!("lea {}, [rip + {}]", out(reg) result, sym $s); + result + } + } +} +macro_rules! static_tls_addr { + ($s:expr) => { + unsafe { + let result: *const u32; + asm!( + " + # Load TLS base address + mov {out}, qword ptr fs:[0] + # Calculate the address of sym in the TLS block. The @tpoff + # relocation gives the offset of the symbol from the start + # of the TLS block. + lea {out}, [{out} + {sym}@tpoff] + ", + out = out(reg) result, + sym = sym $s + ); + result + } + } +} + +static S1: u32 = 111; +#[thread_local] +static S2: u32 = 222; + +fn main() { + assert_eq!(call!(f1), 111); + assert_eq!(call!(f2), 222); + assert_eq!(static_addr!(S1), &S1 as *const u32); + assert_eq!(static_tls_addr!(S2), &S2 as *const u32); + std::thread::spawn(|| { + assert_eq!(static_addr!(S1), &S1 as *const u32); + assert_eq!(static_tls_addr!(S2), &S2 as *const u32); + }) + .join() + .unwrap(); +} diff --git a/src/test/ui/asm/x86_64/target-feature-attr.rs b/src/test/ui/asm/x86_64/target-feature-attr.rs new file mode 100644 index 000000000..14490c3e0 --- /dev/null +++ b/src/test/ui/asm/x86_64/target-feature-attr.rs @@ -0,0 +1,42 @@ +// only-x86_64 + +#![feature(avx512_target_feature)] + +use std::arch::asm; + +#[target_feature(enable = "avx")] +unsafe fn foo() { + let mut x = 1; + let y = 2; + asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); + assert_eq!(x, 3); +} + +unsafe fn bar() { + let mut x = 1; + let y = 2; + asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); + //~^ ERROR: register class `ymm_reg` requires the `avx` target feature + //~| ERROR: register class `ymm_reg` requires the `avx` target feature + //~| ERROR: register class `ymm_reg` requires the `avx` target feature + assert_eq!(x, 3); +} + +#[target_feature(enable = "avx512bw")] +unsafe fn baz() { + let x = 1; + asm!("/* {0} */", in(kreg) x); +} + +unsafe fn baz2() { + let x = 1; + asm!("/* {0} */", in(kreg) x); + //~^ ERROR: register class `kreg` requires at least one of the following target features: avx512bw, avx512f +} + +fn main() { + unsafe { + foo(); + bar(); + } +} diff --git a/src/test/ui/asm/x86_64/target-feature-attr.stderr b/src/test/ui/asm/x86_64/target-feature-attr.stderr new file mode 100644 index 000000000..c852726ee --- /dev/null +++ b/src/test/ui/asm/x86_64/target-feature-attr.stderr @@ -0,0 +1,26 @@ +error: register class `ymm_reg` requires the `avx` target feature + --> $DIR/target-feature-attr.rs:18:40 + | +LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); + | ^^^^^^^^^^^^^ + +error: register class `ymm_reg` requires the `avx` target feature + --> $DIR/target-feature-attr.rs:18:55 + | +LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); + | ^^^^^^^^^^^^^ + +error: register class `ymm_reg` requires the `avx` target feature + --> $DIR/target-feature-attr.rs:18:70 + | +LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x); + | ^^^^^^^^^^^^^^^^^^ + +error: register class `kreg` requires at least one of the following target features: avx512bw, avx512f + --> $DIR/target-feature-attr.rs:33:23 + | +LL | asm!("/* {0} */", in(kreg) x); + | ^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/asm/x86_64/type-check-2.rs b/src/test/ui/asm/x86_64/type-check-2.rs new file mode 100644 index 000000000..59d8cde3f --- /dev/null +++ b/src/test/ui/asm/x86_64/type-check-2.rs @@ -0,0 +1,87 @@ +// only-x86_64 + +#![feature(repr_simd, never_type, asm_sym)] + +use std::arch::{asm, global_asm}; + +#[repr(simd)] +struct SimdNonCopy(f32, f32, f32, f32); + +fn main() { + unsafe { + // Inputs must be initialized + + let x: u64; + asm!("{}", in(reg) x); + let mut y: u64; + asm!("{}", inout(reg) y); + let _ = y; + + // Outputs require mutable places + + let v: Vec<u64> = vec![0, 1, 2]; + asm!("{}", in(reg) v[0]); + asm!("{}", out(reg) v[0]); + asm!("{}", inout(reg) v[0]); + + // Sym operands must point to a function or static + + const C: i32 = 0; + static S: i32 = 0; + asm!("{}", sym S); + asm!("{}", sym main); + asm!("{}", sym C); + //~^ ERROR invalid `sym` operand + asm!("{}", sym x); + //~^ ERROR invalid `sym` operand + + // Register operands must be Copy + + asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); + //~^ ERROR arguments for inline assembly must be copyable + + // Register operands must be integers, floats, SIMD vectors, pointers or + // function pointers. + + asm!("{}", in(reg) 0i64); + asm!("{}", in(reg) 0f64); + asm!("{}", in(xmm_reg) std::arch::x86_64::_mm_setzero_ps()); + asm!("{}", in(reg) 0 as *const u8); + asm!("{}", in(reg) 0 as *mut u8); + asm!("{}", in(reg) main as fn()); + asm!("{}", in(reg) |x: i32| x); + //~^ ERROR cannot use value of type + asm!("{}", in(reg) vec![0]); + //~^ ERROR cannot use value of type `Vec<i32>` for inline assembly + asm!("{}", in(reg) (1, 2, 3)); + //~^ ERROR cannot use value of type `(i32, i32, i32)` for inline assembly + asm!("{}", in(reg) [1, 2, 3]); + //~^ ERROR cannot use value of type `[i32; 3]` for inline assembly + + // Register inputs (but not outputs) allow references and function types + + let mut f = main; + let mut r = &mut 0; + asm!("{}", in(reg) f); + asm!("{}", inout(reg) f); + //~^ ERROR cannot use value of type `fn() {main}` for inline assembly + asm!("{}", in(reg) r); + asm!("{}", inout(reg) r); + //~^ ERROR cannot use value of type `&mut i32` for inline assembly + let _ = (f, r); + + // Type checks ignore never type + + let u: ! = unreachable!(); + asm!("{}", in(reg) u); + } +} + +// Sym operands must point to a function or static + +const C: i32 = 0; +static S: i32 = 0; +global_asm!("{}", sym S); +global_asm!("{}", sym main); +global_asm!("{}", sym C); +//~^ ERROR invalid `sym` operand diff --git a/src/test/ui/asm/x86_64/type-check-2.stderr b/src/test/ui/asm/x86_64/type-check-2.stderr new file mode 100644 index 000000000..d9ca25519 --- /dev/null +++ b/src/test/ui/asm/x86_64/type-check-2.stderr @@ -0,0 +1,83 @@ +error: invalid `sym` operand + --> $DIR/type-check-2.rs:35:24 + | +LL | asm!("{}", sym x); + | ^ is a local variable + | + = help: `sym` operands must refer to either a function or a static + +error: invalid `sym` operand + --> $DIR/type-check-2.rs:86:19 + | +LL | global_asm!("{}", sym C); + | ^^^^^ is an `i32` + | + = help: `sym` operands must refer to either a function or a static + +error: invalid `sym` operand + --> $DIR/type-check-2.rs:33:20 + | +LL | asm!("{}", sym C); + | ^^^^^ is an `i32` + | + = help: `sym` operands must refer to either a function or a static + +error: arguments for inline assembly must be copyable + --> $DIR/type-check-2.rs:40:32 + | +LL | asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `SimdNonCopy` does not implement the Copy trait + +error: cannot use value of type `[closure@$DIR/type-check-2.rs:52:28: 52:36]` for inline assembly + --> $DIR/type-check-2.rs:52:28 + | +LL | asm!("{}", in(reg) |x: i32| x); + | ^^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `Vec<i32>` for inline assembly + --> $DIR/type-check-2.rs:54:28 + | +LL | asm!("{}", in(reg) vec![0]); + | ^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot use value of type `(i32, i32, i32)` for inline assembly + --> $DIR/type-check-2.rs:56:28 + | +LL | asm!("{}", in(reg) (1, 2, 3)); + | ^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `[i32; 3]` for inline assembly + --> $DIR/type-check-2.rs:58:28 + | +LL | asm!("{}", in(reg) [1, 2, 3]); + | ^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `fn() {main}` for inline assembly + --> $DIR/type-check-2.rs:66:31 + | +LL | asm!("{}", inout(reg) f); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `&mut i32` for inline assembly + --> $DIR/type-check-2.rs:69:31 + | +LL | asm!("{}", inout(reg) r); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/asm/x86_64/type-check-3.rs b/src/test/ui/asm/x86_64/type-check-3.rs new file mode 100644 index 000000000..89c849c75 --- /dev/null +++ b/src/test/ui/asm/x86_64/type-check-3.rs @@ -0,0 +1,73 @@ +// only-x86_64 +// compile-flags: -C target-feature=+avx512f + +#![feature(asm_const)] + +use std::arch::{asm, global_asm}; + +use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps}; + +fn main() { + unsafe { + // Types must be listed in the register class. + + asm!("{}", in(reg) 0i128); + //~^ ERROR type `i128` cannot be used with this register class + asm!("{}", in(reg) _mm_setzero_ps()); + //~^ ERROR type `__m128` cannot be used with this register class + asm!("{}", in(reg) _mm256_setzero_ps()); + //~^ ERROR type `__m256` cannot be used with this register class + asm!("{}", in(xmm_reg) 0u8); + //~^ ERROR type `u8` cannot be used with this register class + asm!("{:e}", in(reg) 0i32); + asm!("{}", in(xmm_reg) 0i32); + asm!("{:e}", in(reg) 0f32); + asm!("{}", in(xmm_reg) 0f32); + asm!("{}", in(xmm_reg) _mm_setzero_ps()); + asm!("{:x}", in(ymm_reg) _mm_setzero_ps()); + asm!("{}", in(kreg) 0u16); + asm!("{}", in(kreg) 0u64); + //~^ ERROR `avx512bw` target feature is not enabled + + // Template modifier suggestions for sub-registers + + asm!("{0} {0}", in(reg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{0} {0:x}", in(reg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0i32); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0i64); + asm!("{}", in(ymm_reg) 0i64); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(ymm_reg) _mm256_setzero_ps()); + asm!("{:l}", in(reg) 0i16); + asm!("{:l}", in(reg) 0i32); + asm!("{:l}", in(reg) 0i64); + asm!("{:x}", in(ymm_reg) 0i64); + asm!("{:x}", in(ymm_reg) _mm256_setzero_ps()); + + // Suggest different register class for type + + asm!("{}", in(reg) 0i8); + //~^ ERROR type `i8` cannot be used with this register class + asm!("{}", in(reg_byte) 0i8); + + // Split inout operands must have compatible types + + let mut val_i16: i16; + let mut val_f32: f32; + let mut val_u32: u32; + let mut val_u64: u64; + let mut val_ptr: *mut u8; + asm!("{:r}", inout(reg) 0u16 => val_i16); + asm!("{:r}", inout(reg) 0u32 => val_f32); + //~^ ERROR incompatible types for asm inout argument + asm!("{:r}", inout(reg) 0u32 => val_ptr); + //~^ ERROR incompatible types for asm inout argument + asm!("{:r}", inout(reg) main => val_u32); + //~^ ERROR incompatible types for asm inout argument + asm!("{:r}", inout(reg) 0u64 => val_ptr); + asm!("{:r}", inout(reg) main => val_u64); + } +} diff --git a/src/test/ui/asm/x86_64/type-check-3.stderr b/src/test/ui/asm/x86_64/type-check-3.stderr new file mode 100644 index 000000000..b38ea8cc4 --- /dev/null +++ b/src/test/ui/asm/x86_64/type-check-3.stderr @@ -0,0 +1,118 @@ +error: type `i128` cannot be used with this register class + --> $DIR/type-check-3.rs:14:28 + | +LL | asm!("{}", in(reg) 0i128); + | ^^^^^ + | + = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + +error: type `__m128` cannot be used with this register class + --> $DIR/type-check-3.rs:16:28 + | +LL | asm!("{}", in(reg) _mm_setzero_ps()); + | ^^^^^^^^^^^^^^^^ + | + = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + +error: type `__m256` cannot be used with this register class + --> $DIR/type-check-3.rs:18:28 + | +LL | asm!("{}", in(reg) _mm256_setzero_ps()); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + +error: type `u8` cannot be used with this register class + --> $DIR/type-check-3.rs:20:32 + | +LL | asm!("{}", in(xmm_reg) 0u8); + | ^^^ + | + = note: register class `xmm_reg` supports these types: i32, i64, f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + +error: `avx512bw` target feature is not enabled + --> $DIR/type-check-3.rs:29:29 + | +LL | asm!("{}", in(kreg) 0u64); + | ^^^^ + | + = note: this is required to use type `u64` with register class `kreg` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:34:15 + | +LL | asm!("{0} {0}", in(reg) 0i16); + | ^^^ ^^^ ---- for this argument + | + = note: `#[warn(asm_sub_register)]` on by default + = help: use the `x` modifier to have the register formatted as `ax` + = help: or use the `r` modifier to keep the default formatting of `rax` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:36:15 + | +LL | asm!("{0} {0:x}", in(reg) 0i16); + | ^^^ ---- for this argument + | + = help: use the `x` modifier to have the register formatted as `ax` + = help: or use the `r` modifier to keep the default formatting of `rax` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:38:15 + | +LL | asm!("{}", in(reg) 0i32); + | ^^ ---- for this argument + | + = help: use the `e` modifier to have the register formatted as `eax` + = help: or use the `r` modifier to keep the default formatting of `rax` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:41:15 + | +LL | asm!("{}", in(ymm_reg) 0i64); + | ^^ ---- for this argument + | + = help: use the `x` modifier to have the register formatted as `xmm0` + = help: or use the `y` modifier to keep the default formatting of `ymm0` + +error: type `i8` cannot be used with this register class + --> $DIR/type-check-3.rs:52:28 + | +LL | asm!("{}", in(reg) 0i8); + | ^^^ + | + = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = help: consider using the `reg_byte` register class instead + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:64:33 + | +LL | asm!("{:r}", inout(reg) 0u32 => val_f32); + | ^^^^ ^^^^^^^ type `f32` + | | + | type `u32` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:66:33 + | +LL | asm!("{:r}", inout(reg) 0u32 => val_ptr); + | ^^^^ ^^^^^^^ type `*mut u8` + | | + | type `u32` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:68:33 + | +LL | asm!("{:r}", inout(reg) main => val_u32); + | ^^^^ ^^^^^^^ type `u32` + | | + | type `fn()` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error: aborting due to 9 previous errors; 4 warnings emitted + diff --git a/src/test/ui/asm/x86_64/type-check-4.rs b/src/test/ui/asm/x86_64/type-check-4.rs new file mode 100644 index 000000000..da3b76c3d --- /dev/null +++ b/src/test/ui/asm/x86_64/type-check-4.rs @@ -0,0 +1,29 @@ +// only-x86_64 +// compile-flags: -C target-feature=+avx512f + +#![feature(asm_const, asm_sym)] + +use std::arch::{asm, global_asm}; + +use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps}; + +fn main() { +} + +// Constants must be... constant + +static S: i32 = 1; +const fn const_foo(x: i32) -> i32 { + x +} +const fn const_bar<T>(x: T) -> T { + x +} +global_asm!("{}", const S); +//~^ ERROR constants cannot refer to statics +global_asm!("{}", const const_foo(0)); +global_asm!("{}", const const_foo(S)); +//~^ ERROR constants cannot refer to statics +global_asm!("{}", const const_bar(0)); +global_asm!("{}", const const_bar(S)); +//~^ ERROR constants cannot refer to statics diff --git a/src/test/ui/asm/x86_64/type-check-4.stderr b/src/test/ui/asm/x86_64/type-check-4.stderr new file mode 100644 index 000000000..33f4638fb --- /dev/null +++ b/src/test/ui/asm/x86_64/type-check-4.stderr @@ -0,0 +1,27 @@ +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-4.rs:22:25 + | +LL | global_asm!("{}", const S); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-4.rs:25:35 + | +LL | global_asm!("{}", const const_foo(S)); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-4.rs:28:35 + | +LL | global_asm!("{}", const const_bar(S)); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0013`. diff --git a/src/test/ui/asm/x86_64/type-check-5.rs b/src/test/ui/asm/x86_64/type-check-5.rs new file mode 100644 index 000000000..6190e0b52 --- /dev/null +++ b/src/test/ui/asm/x86_64/type-check-5.rs @@ -0,0 +1,63 @@ +// only-x86_64 + +#![feature(repr_simd, never_type, asm_sym)] + +use std::arch::asm; + +#[repr(simd)] +struct SimdNonCopy(f32, f32, f32, f32); + +fn main() { + unsafe { + // Inputs must be initialized + + let x: u64; + asm!("{}", in(reg) x); + //~^ ERROR E0381 + let mut y: u64; + asm!("{}", inout(reg) y); + //~^ ERROR E0381 + let _ = y; + + // Outputs require mutable places + + let v: Vec<u64> = vec![0, 1, 2]; + asm!("{}", in(reg) v[0]); + asm!("{}", out(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + asm!("{}", inout(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + + // Sym operands must point to a function or static + + const C: i32 = 0; + static S: i32 = 0; + asm!("{}", sym S); + asm!("{}", sym main); + + // Register operands must be Copy + + // Register operands must be integers, floats, SIMD vectors, pointers or + // function pointers. + + asm!("{}", in(reg) 0i64); + asm!("{}", in(reg) 0f64); + asm!("{}", in(xmm_reg) std::arch::x86_64::_mm_setzero_ps()); + asm!("{}", in(reg) 0 as *const u8); + asm!("{}", in(reg) 0 as *mut u8); + asm!("{}", in(reg) main as fn()); + + // Register inputs (but not outputs) allow references and function types + + let mut f = main; + let mut r = &mut 0; + asm!("{}", in(reg) f); + asm!("{}", in(reg) r); + let _ = (f, r); + + // Type checks ignore never type + + let u: ! = unreachable!(); + asm!("{}", in(reg) u); + } +} diff --git a/src/test/ui/asm/x86_64/type-check-5.stderr b/src/test/ui/asm/x86_64/type-check-5.stderr new file mode 100644 index 000000000..e9c93fea5 --- /dev/null +++ b/src/test/ui/asm/x86_64/type-check-5.stderr @@ -0,0 +1,38 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/type-check-5.rs:15:28 + | +LL | let x: u64; + | - binding declared here but left uninitialized +LL | asm!("{}", in(reg) x); + | ^ `x` used here but it isn't initialized + +error[E0381]: used binding `y` isn't initialized + --> $DIR/type-check-5.rs:18:9 + | +LL | let mut y: u64; + | ----- binding declared here but left uninitialized +LL | asm!("{}", inout(reg) y); + | ^^^^^^^^^^^^^^^^^^^^^^^^ `y` used here but it isn't initialized + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-5.rs:26:29 + | +LL | let v: Vec<u64> = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +LL | asm!("{}", in(reg) v[0]); +LL | asm!("{}", out(reg) v[0]); + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-5.rs:28:31 + | +LL | let v: Vec<u64> = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +... +LL | asm!("{}", inout(reg) v[0]); + | ^ cannot borrow as mutable + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0381, E0596. +For more information about an error, try `rustc --explain E0381`. |