Auto merge of #69171 - Amanieu:new-asm, r=nagisa,nikomatsakis

Implement new asm! syntax from RFC 2850

This PR implements the new `asm!` syntax proposed in https://github.com/rust-lang/rfcs/pull/2850.

# Design

A large part of this PR revolves around taking an `asm!` macro invocation and plumbing it through all of the compiler layers down to LLVM codegen. Throughout the various stages, an `InlineAsm` generally consists of 3 components:

- The template string, which is stored as an array of `InlineAsmTemplatePiece`. Each piece represents either a literal or a placeholder for an operand (just like format strings).
```rust
pub enum InlineAsmTemplatePiece {
    String(String),
    Placeholder { operand_idx: usize, modifier: Option<char>, span: Span },
}
```

- The list of operands to the `asm!` (`in`, `[late]out`, `in[late]out`, `sym`, `const`). These are represented differently at each stage of lowering, but follow a common pattern:
  - `in`, `out` and `inout` all have an associated register class (`reg`) or explicit register (`"eax"`).
  - `inout` has 2 forms: one with a single expression that is both read from and written to, and one with two separate expressions for the input and output parts.
  - `out` and `inout` have a `late` flag (`lateout` / `inlateout`) to indicate that the register allocator is allowed to reuse an input register for this output.
  - `out` and the split variant of `inout` allow `_` to be specified for an output, which means that the output is discarded. This is used to allocate scratch registers for assembly code.
  - `sym` is a bit special since it only accepts a path expression, which must point to a `static` or a `fn`.

- The options set at the end of the `asm!` macro. The only one that is particularly of interest to rustc is `NORETURN` which makes `asm!` return `!` instead of `()`.
```rust
bitflags::bitflags! {
    pub struct InlineAsmOptions: u8 {
        const PURE = 1 << 0;
        const NOMEM = 1 << 1;
        const READONLY = 1 << 2;
        const PRESERVES_FLAGS = 1 << 3;
        const NORETURN = 1 << 4;
        const NOSTACK = 1 << 5;
    }
}
```

## AST

`InlineAsm` is represented as an expression in the AST:

```rust
pub struct InlineAsm {
    pub template: Vec<InlineAsmTemplatePiece>,
    pub operands: Vec<(InlineAsmOperand, Span)>,
    pub options: InlineAsmOptions,
}

pub enum InlineAsmRegOrRegClass {
    Reg(Symbol),
    RegClass(Symbol),
}

pub enum InlineAsmOperand {
    In {
        reg: InlineAsmRegOrRegClass,
        expr: P<Expr>,
    },
    Out {
        reg: InlineAsmRegOrRegClass,
        late: bool,
        expr: Option<P<Expr>>,
    },
    InOut {
        reg: InlineAsmRegOrRegClass,
        late: bool,
        expr: P<Expr>,
    },
    SplitInOut {
        reg: InlineAsmRegOrRegClass,
        late: bool,
        in_expr: P<Expr>,
        out_expr: Option<P<Expr>>,
    },
    Const {
        expr: P<Expr>,
    },
    Sym {
        expr: P<Expr>,
    },
}
```

The `asm!` macro is implemented in librustc_builtin_macros and outputs an `InlineAsm` AST node. The template string is parsed using libfmt_macros, positional and named operands are resolved to explicit operand indicies. Since target information is not available to macro invocations, validation of the registers and register classes is deferred to AST lowering.

## HIR

`InlineAsm` is represented as an expression in the HIR:

```rust
pub struct InlineAsm<'hir> {
    pub template: &'hir [InlineAsmTemplatePiece],
    pub operands: &'hir [InlineAsmOperand<'hir>],
    pub options: InlineAsmOptions,
}

pub enum InlineAsmRegOrRegClass {
    Reg(InlineAsmReg),
    RegClass(InlineAsmRegClass),
}

pub enum InlineAsmOperand<'hir> {
    In {
        reg: InlineAsmRegOrRegClass,
        expr: Expr<'hir>,
    },
    Out {
        reg: InlineAsmRegOrRegClass,
        late: bool,
        expr: Option<Expr<'hir>>,
    },
    InOut {
        reg: InlineAsmRegOrRegClass,
        late: bool,
        expr: Expr<'hir>,
    },
    SplitInOut {
        reg: InlineAsmRegOrRegClass,
        late: bool,
        in_expr: Expr<'hir>,
        out_expr: Option<Expr<'hir>>,
    },
    Const {
        expr: Expr<'hir>,
    },
    Sym {
        expr: Expr<'hir>,
    },
}
```

AST lowering is where `InlineAsmRegOrRegClass` is converted from `Symbol`s to an actual register or register class. If any modifiers are specified for a template string placeholder, these are validated against the set allowed for that operand type. Finally, explicit registers for inputs and outputs are checked for conflicts (same register used for different operands).

## Type checking

Each register class has a whitelist of types that it may be used with. After the types of all operands have been determined, the `intrinsicck` pass will check that these types are in the whitelist. It also checks that split `inout` operands have compatible types and that `const` operands are integers or floats. Suggestions are emitted where needed if a template modifier should be used for an operand based on the type that was passed into it.

## HAIR

`InlineAsm` is represented as an expression in the HAIR:

```rust
crate enum ExprKind<'tcx> {
    // [..]
    InlineAsm {
        template: &'tcx [InlineAsmTemplatePiece],
        operands: Vec<InlineAsmOperand<'tcx>>,
        options: InlineAsmOptions,
    },
}
crate enum InlineAsmOperand<'tcx> {
    In {
        reg: InlineAsmRegOrRegClass,
        expr: ExprRef<'tcx>,
    },
    Out {
        reg: InlineAsmRegOrRegClass,
        late: bool,
        expr: Option<ExprRef<'tcx>>,
    },
    InOut {
        reg: InlineAsmRegOrRegClass,
        late: bool,
        expr: ExprRef<'tcx>,
    },
    SplitInOut {
        reg: InlineAsmRegOrRegClass,
        late: bool,
        in_expr: ExprRef<'tcx>,
        out_expr: Option<ExprRef<'tcx>>,
    },
    Const {
        expr: ExprRef<'tcx>,
    },
    SymFn {
        expr: ExprRef<'tcx>,
    },
    SymStatic {
        expr: ExprRef<'tcx>,
    },
}
```

The only significant change compared to HIR is that `Sym` has been lowered to either a `SymFn` whose `expr` is a `Literal` ZST of the `fn`, or a `SymStatic` whose `expr` is a `StaticRef`.

## MIR

`InlineAsm` is represented as a `Terminator` in the MIR:

```rust
pub enum TerminatorKind<'tcx> {
    // [..]

    /// Block ends with an inline assembly block. This is a terminator since
    /// inline assembly is allowed to diverge.
    InlineAsm {
        /// The template for the inline assembly, with placeholders.
        template: &'tcx [InlineAsmTemplatePiece],

        /// The operands for the inline assembly, as `Operand`s or `Place`s.
        operands: Vec<InlineAsmOperand<'tcx>>,

        /// Miscellaneous options for the inline assembly.
        options: InlineAsmOptions,

        /// Destination block after the inline assembly returns, unless it is
        /// diverging (InlineAsmOptions::NORETURN).
        destination: Option<BasicBlock>,
    },
}

pub enum InlineAsmOperand<'tcx> {
    In {
        reg: InlineAsmRegOrRegClass,
        value: Operand<'tcx>,
    },
    Out {
        reg: InlineAsmRegOrRegClass,
        late: bool,
        place: Option<Place<'tcx>>,
    },
    InOut {
        reg: InlineAsmRegOrRegClass,
        late: bool,
        in_value: Operand<'tcx>,
        out_place: Option<Place<'tcx>>,
    },
    Const {
        value: Operand<'tcx>,
    },
    SymFn {
        value: Box<Constant<'tcx>>,
    },
    SymStatic {
        value: Box<Constant<'tcx>>,
    },
}
```

As part of HAIR lowering, `InOut` and `SplitInOut` operands are lowered to a split form with a separate `in_value` and `out_place`.

Semantically, the `InlineAsm` terminator is similar to the `Call` terminator except that it has multiple output places where a `Call` only has a single return place output.

The constant promotion pass is used to ensure that `const` operands are actually constants (using the same logic as `#[rustc_args_required_const]`).

## Codegen

Operands are lowered one more time before being passed to LLVM codegen:

```rust
pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> {
    In {
        reg: InlineAsmRegOrRegClass,
        value: OperandRef<'tcx, B::Value>,
    },
    Out {
        reg: InlineAsmRegOrRegClass,
        late: bool,
        place: Option<PlaceRef<'tcx, B::Value>>,
    },
    InOut {
        reg: InlineAsmRegOrRegClass,
        late: bool,
        in_value: OperandRef<'tcx, B::Value>,
        out_place: Option<PlaceRef<'tcx, B::Value>>,
    },
    Const {
        string: String,
    },
    SymFn {
        instance: Instance<'tcx>,
    },
    SymStatic {
        def_id: DefId,
    },
}
```

The operands are lowered to LLVM operands and constraint codes as follow:
- `out` and the output part of `inout` operands are added first, as required by LLVM. Late output operands have a `=` prefix added to their constraint code, non-late output operands have a `=&` prefix added to their constraint code.
- `in` operands are added normally.
- `inout` operands are tied to the matching output operand.
- `sym` operands are passed as function pointers or pointers, using the `"s"` constraint.
- `const` operands are formatted to a string and directly inserted in the template string.

The template string is converted to LLVM form:
- `$` characters are escaped as `$$`.
- `const` operands are converted to strings and inserted directly.
- Placeholders are formatted as `${X:M}` where `X` is the operand index and `M` is the modifier character. Modifiers are converted from the Rust form to the LLVM form.

The various options are converted to clobber constraints or LLVM attributes, refer to the [RFC](https://github.com/Amanieu/rfcs/blob/inline-asm/text/0000-inline-asm.md#mapping-to-llvm-ir) for more details.

Note that LLVM is sometimes rather picky about what types it accepts for certain constraint codes so we sometimes need to insert conversions to/from a supported type. See the target-specific ISelLowering.cpp files in LLVM for details.

# Adding support for new architectures

Adding inline assembly support to an architecture is mostly a matter of defining the registers and register classes for that architecture. All the definitions for register classes are located in `src/librustc_target/asm/`.

Additionally you will need to implement lowering of these register classes to LLVM constraint codes in `src/librustc_codegen_llvm/asm.rs`.
This commit is contained in:
bors 2020-05-19 18:32:40 +00:00
commit 3a7dfda40a
140 changed files with 9285 additions and 279 deletions

View file

@ -0,0 +1,18 @@
// only-x86_64
#![feature(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 `pure` option must have at least one output
asm!("{}", in(reg) foo, options(pure, nomem));
//~^ ERROR asm with `pure` option must have at least one output
asm!("{}", out(reg) foo, options(noreturn));
//~^ ERROR asm outputs are not allowed with the `noreturn` option
}
}

View file

@ -0,0 +1,32 @@
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 `pure` option must have at least one output
--> $DIR/bad-options.rs:10:18
|
LL | asm!("", options(pure, nomem, noreturn));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: asm with `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: aborting due to 5 previous errors

View file

@ -0,0 +1,55 @@
// only-x86_64
// compile-flags: -C target-feature=+avx2
#![feature(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(zmm_reg) foo);
//~^ ERROR register class `zmm_reg` requires the `avx512f` target feature
asm!("", in("zmm0") foo);
//~^ ERROR register class `zmm_reg` requires the `avx512f` target feature
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 invalid register `st(2)`: x87 registers are not currently supported as operands
asm!("", in("mm0") foo);
//~^ ERROR invalid register `mm0`: MMX registers are not currently supported as operands
asm!("", in("k0") foo);
//~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand
// Explicit register conflicts
// (except in/lateout which don't conflict)
asm!("", in("eax") foo, in("al") bar);
//~^ ERROR register `al` conflicts with register `ax`
asm!("", in("rax") foo, out("rax") bar);
//~^ ERROR register `ax` conflicts with register `ax`
asm!("", in("al") foo, lateout("al") bar);
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);
}
}

View file

@ -0,0 +1,142 @@
error: invalid register class `foo`: unknown register class
--> $DIR/bad-reg.rs:12:20
|
LL | asm!("{}", in(foo) foo);
| ^^^^^^^^^^^
error: invalid register `foo`: unknown register
--> $DIR/bad-reg.rs:14:18
|
LL | asm!("", in("foo") foo);
| ^^^^^^^^^^^^^
error: invalid asm template modifier for this register class
--> $DIR/bad-reg.rs:16: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:18: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:20:15
|
LL | asm!("{:a}", const 0);
| ^^^^ ------- argument
| |
| template modifier
error: asm template modifiers are not allowed for `sym` arguments
--> $DIR/bad-reg.rs:22:15
|
LL | asm!("{:a}", sym main);
| ^^^^ -------- argument
| |
| template modifier
error: register class `zmm_reg` requires the `avx512f` target feature
--> $DIR/bad-reg.rs:24:20
|
LL | asm!("{}", in(zmm_reg) foo);
| ^^^^^^^^^^^^^^^
error: register class `zmm_reg` requires the `avx512f` target feature
--> $DIR/bad-reg.rs:26:18
|
LL | asm!("", in("zmm0") foo);
| ^^^^^^^^^^^^^^
error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:28: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:30: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:32:18
|
LL | asm!("", in("ip") foo);
| ^^^^^^^^^^^^
error: invalid register `st(2)`: x87 registers are not currently supported as operands for inline asm
--> $DIR/bad-reg.rs:34:18
|
LL | asm!("", in("st(2)") foo);
| ^^^^^^^^^^^^^^^
error: invalid register `mm0`: MMX registers are not currently supported as operands for inline asm
--> $DIR/bad-reg.rs:36:18
|
LL | asm!("", in("mm0") foo);
| ^^^^^^^^^^^^^
error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:38:18
|
LL | asm!("", in("k0") foo);
| ^^^^^^^^^^^^
error: register `al` conflicts with register `ax`
--> $DIR/bad-reg.rs:44:33
|
LL | asm!("", in("eax") foo, in("al") bar);
| ------------- ^^^^^^^^^^^^ register `al`
| |
| register `ax`
error: register `ax` conflicts with register `ax`
--> $DIR/bad-reg.rs:46: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:46:18
|
LL | asm!("", in("rax") foo, out("rax") bar);
| ^^^^^^^^^^^^^
error: register `ymm0` conflicts with register `xmm0`
--> $DIR/bad-reg.rs:49:34
|
LL | asm!("", in("xmm0") foo, in("ymm0") bar);
| -------------- ^^^^^^^^^^^^^^ register `ymm0`
| |
| register `xmm0`
error: register `ymm0` conflicts with register `xmm0`
--> $DIR/bad-reg.rs:51: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:51:18
|
LL | asm!("", in("xmm0") foo, out("ymm0") bar);
| ^^^^^^^^^^^^^^
error: aborting due to 18 previous errors

View file

@ -0,0 +1,26 @@
// only-x86_64
#![feature(asm)]
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
asm!("{}", in("eax") foo);
//~^ ERROR invalid reference to argument at index 0
asm!("{:foo}", in(reg) foo);
//~^ ERROR asm template modifier must be a single character
}
}

View file

@ -0,0 +1,86 @@
error: invalid reference to argument at index 0
--> $DIR/bad-template.rs:8:15
|
LL | asm!("{}");
| ^^ from here
|
= note: no arguments were given
error: invalid reference to argument at index 1
--> $DIR/bad-template.rs:10:15
|
LL | asm!("{1}", in(reg) foo);
| ^^^ from here
|
= note: there is 1 argument
error: argument never used
--> $DIR/bad-template.rs:10:21
|
LL | asm!("{1}", in(reg) foo);
| ^^^^^^^^^^^ argument never used
error: there is no argument named `a`
--> $DIR/bad-template.rs:13:15
|
LL | asm!("{a}");
| ^^^
error: invalid reference to argument at index 0
--> $DIR/bad-template.rs:15: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:15:20
|
LL | asm!("{}", a = in(reg) foo);
| ^^^^^^^^^^^^^^^
error: named argument never used
--> $DIR/bad-template.rs:15:20
|
LL | asm!("{}", a = in(reg) foo);
| ^^^^^^^^^^^^^^^ named argument never used
error: invalid reference to argument at index 1
--> $DIR/bad-template.rs:18: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:18:21
|
LL | asm!("{1}", a = in(reg) foo);
| ^^^^^^^^^^^^^^^ named argument never used
error: invalid reference to argument at index 0
--> $DIR/bad-template.rs:21: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:21:20
|
LL | asm!("{}", in("eax") foo);
| ^^^^^^^^^^^^^
error: asm template modifier must be a single character
--> $DIR/bad-template.rs:23:17
|
LL | asm!("{:foo}", in(reg) foo);
| ^^^
error: aborting due to 10 previous errors

56
src/test/ui/asm/const.rs Normal file
View file

@ -0,0 +1,56 @@
// no-system-llvm
// only-x86_64
// run-pass
#![feature(asm)]
use std::mem::size_of;
trait Proj {
const C: usize;
}
impl Proj for i8 {
const C: usize = 8;
}
impl Proj for i16 {
const C: usize = 16;
}
const fn constfn(x: usize) -> usize {
x
}
fn generic<T: Proj>() {
unsafe {
let a: usize;
asm!("mov {}, {}", out(reg) a, const size_of::<T>());
assert_eq!(a, size_of::<T>());
let b: usize;
asm!("mov {}, {}", out(reg) b, const size_of::<T>() + constfn(5));
assert_eq!(b, size_of::<T>() + 5);
let c: usize;
asm!("mov {}, {}", out(reg) c, const T::C);
assert_eq!(c, T::C);
}
}
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);
}
generic::<i8>();
generic::<i16>();
}

View file

@ -0,0 +1,17 @@
// only-x86_64
// check-pass
#![feature(asm, never_type)]
#![crate_type = "rlib"]
pub unsafe fn asm1() {
let _: () = asm!("");
}
pub unsafe fn asm2() {
let _: ! = asm!("", options(noreturn));
}
pub unsafe fn asm3() -> ! {
asm!("", options(noreturn));
}

View file

@ -0,0 +1,56 @@
// only-x86_64
#![feature(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 one of
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 argument to `sym` must be a path expression
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(), options());
//~^ ERROR asm options cannot be specified multiple times
asm!("", options(), options(), options());
//~^ ERROR asm options cannot be specified multiple times
//~^^ ERROR asm options cannot be specified multiple times
asm!("{}", options(), const foo);
//~^ ERROR arguments are not allowed after options
asm!("{a}", a = const foo, a = const bar);
//~^ ERROR duplicate argument named `a`
//~^^ ERROR argument never used
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
asm!("{a}", in("eax") foo, a = const bar);
//~^ ERROR named arguments cannot follow explicit register arguments
asm!("{1}", in("eax") foo, const bar);
//~^ ERROR positional arguments cannot follow named arguments or explicit register arguments
}
}

View file

@ -0,0 +1,162 @@
error: requires at least a template string argument
--> $DIR/parse-error.rs:9:9
|
LL | asm!();
| ^^^^^^^
error: asm template must be a string literal
--> $DIR/parse-error.rs:11:14
|
LL | asm!(foo);
| ^^^
error: expected token: `,`
--> $DIR/parse-error.rs:13:19
|
LL | asm!("{}" foo);
| ^^^ expected `,`
error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `foo`
--> $DIR/parse-error.rs:15:20
|
LL | asm!("{}", foo);
| ^^^ expected one of 8 possible tokens
error: expected `(`, found `foo`
--> $DIR/parse-error.rs:17:23
|
LL | asm!("{}", in foo);
| ^^^ expected `(`
error: expected `)`, found `foo`
--> $DIR/parse-error.rs:19:27
|
LL | asm!("{}", in(reg foo));
| ^^^ expected `)`
error: expected expression, found end of macro arguments
--> $DIR/parse-error.rs:21:27
|
LL | asm!("{}", in(reg));
| ^ expected expression
error: expected register class or explicit register
--> $DIR/parse-error.rs:23:26
|
LL | asm!("{}", inout(=) foo => bar);
| ^
error: expected expression, found end of macro arguments
--> $DIR/parse-error.rs:25:37
|
LL | asm!("{}", inout(reg) foo =>);
| ^ expected expression
error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
--> $DIR/parse-error.rs:27:32
|
LL | asm!("{}", in(reg) foo => bar);
| ^^ expected one of 7 possible tokens
error: argument to `sym` must be a path expression
--> $DIR/parse-error.rs:29:24
|
LL | asm!("{}", sym foo + bar);
| ^^^^^^^^^
error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, or `readonly`, found `foo`
--> $DIR/parse-error.rs:31:26
|
LL | asm!("", options(foo));
| ^^^ expected one of 8 possible tokens
error: expected one of `)` or `,`, found `foo`
--> $DIR/parse-error.rs:33:32
|
LL | asm!("", options(nomem foo));
| ^^^ expected one of `)` or `,`
error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, or `readonly`, found `foo`
--> $DIR/parse-error.rs:35:33
|
LL | asm!("", options(nomem, foo));
| ^^^ expected one of 8 possible tokens
error: asm options cannot be specified multiple times
--> $DIR/parse-error.rs:37:29
|
LL | asm!("", options(), options());
| --------- ^^^^^^^^^ duplicate options
| |
| previously here
error: asm options cannot be specified multiple times
--> $DIR/parse-error.rs:39:29
|
LL | asm!("", options(), options(), options());
| --------- ^^^^^^^^^ duplicate options
| |
| previously here
error: asm options cannot be specified multiple times
--> $DIR/parse-error.rs:39:40
|
LL | asm!("", options(), options(), options());
| --------- ^^^^^^^^^ duplicate options
| |
| previously here
error: arguments are not allowed after options
--> $DIR/parse-error.rs:42:31
|
LL | asm!("{}", options(), const foo);
| --------- ^^^^^^^^^ argument
| |
| previous options
error: duplicate argument named `a`
--> $DIR/parse-error.rs:44:36
|
LL | asm!("{a}", a = const foo, a = const bar);
| ------------- ^^^^^^^^^^^^^ duplicate argument
| |
| previously here
error: argument never used
--> $DIR/parse-error.rs:44:36
|
LL | asm!("{a}", a = const foo, a = const bar);
| ^^^^^^^^^^^^^ argument never used
error: explicit register arguments cannot have names
--> $DIR/parse-error.rs:47:18
|
LL | asm!("", a = in("eax") foo);
| ^^^^^^^^^^^^^^^^^
error: named arguments cannot follow explicit register arguments
--> $DIR/parse-error.rs:49: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:51: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:53:36
|
LL | asm!("{1}", in("eax") foo, const bar);
| ------------- ^^^^^^^^^ positional argument
| |
| explicit register argument
error: aborting due to 24 previous errors

View file

@ -0,0 +1,16 @@
// run-rustfix
// only-x86_64
#![feature(asm, llvm_asm)]
fn main() {
unsafe {
let x = 1;
let y: i32;
llvm_asm!("" :: "r" (x));
//~^ ERROR legacy asm! syntax is no longer supported
llvm_asm!("" : "=r" (y));
//~^ ERROR legacy asm! syntax is no longer supported
let _ = y;
}
}

View file

@ -0,0 +1,16 @@
// run-rustfix
// only-x86_64
#![feature(asm, llvm_asm)]
fn main() {
unsafe {
let x = 1;
let y: i32;
asm!("" :: "r" (x));
//~^ ERROR legacy asm! syntax is no longer supported
asm!("" : "=r" (y));
//~^ ERROR legacy asm! syntax is no longer supported
let _ = y;
}
}

View file

@ -0,0 +1,18 @@
error: legacy asm! syntax is no longer supported
--> $DIR/rustfix-asm.rs:10:9
|
LL | asm!("" :: "r" (x));
| ----^^^^^^^^^^^^^^^^
| |
| help: replace with: `llvm_asm!`
error: legacy asm! syntax is no longer supported
--> $DIR/rustfix-asm.rs:12:9
|
LL | asm!("" : "=r" (y));
| ----^^^^^^^^^^^^^^^^
| |
| help: replace with: `llvm_asm!`
error: aborting due to 2 previous errors

View file

@ -0,0 +1,25 @@
// only-x86_64
#![feature(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
asm!("{}", out(reg) v[..]);
//~^ ERROR the size for values of type `[u64]` cannot be known at compilation time
asm!("{}", inout(reg) v[..]);
//~^ ERROR the size for values of type `[u64]` cannot be known at compilation time
}
}

View file

@ -0,0 +1,45 @@
error: invalid asm output
--> $DIR/type-check-1.rs:10:29
|
LL | asm!("{}", out(reg) 1 + 2);
| ^^^^^ cannot assign to this expression
error: invalid asm output
--> $DIR/type-check-1.rs:12: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:18:28
|
LL | asm!("{}", in(reg) v[..]);
| ^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u64]`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= 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:20:29
|
LL | asm!("{}", out(reg) v[..]);
| ^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u64]`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= 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:22:31
|
LL | asm!("{}", inout(reg) v[..]);
| ^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u64]`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: all inline asm arguments must have a statically known size
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -0,0 +1,104 @@
// only-x86_64
#![feature(asm, repr_simd, never_type)]
#[repr(simd)]
struct SimdNonCopy(f32, f32, f32, f32);
fn main() {
unsafe {
// Inputs must be initialized
let x: u64;
asm!("{}", in(reg) x);
//~^ ERROR use of possibly-uninitialized variable: `x`
let mut y: u64;
asm!("{}", inout(reg) y);
//~^ ERROR use of possibly-uninitialized variable: `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]);
//~^ 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
// Const operands must be integer or floats, and must be constants.
let x = 0;
const C: i32 = 0;
const fn const_foo(x: i32) -> i32 {
x
}
const fn const_bar<T>(x: T) -> T {
x
}
asm!("{}", const 0i32);
asm!("{}", const 0f32);
asm!("{}", const 0 as *mut u8);
//~^ ERROR asm `const` arguments must be integer or floating-point values
asm!("{}", const &0);
//~^ ERROR asm `const` arguments must be integer or floating-point values
asm!("{}", const x);
//~^ ERROR argument 1 is required to be a constant
asm!("{}", const const_foo(0));
asm!("{}", const const_foo(x));
//~^ ERROR argument 1 is required to be a constant
asm!("{}", const const_bar(0));
asm!("{}", const const_bar(x));
//~^ ERROR argument 1 is required to be a constant
// Sym operands must point to a function or static
static S: i32 = 0;
asm!("{}", sym S);
asm!("{}", sym main);
asm!("{}", sym C);
//~^ ERROR asm `sym` operand must point to a fn or static
asm!("{}", sym x);
//~^ ERROR asm `sym` operand must point to a fn or static
// 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 `std::vec::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);
}
}

View file

@ -0,0 +1,133 @@
error: asm `const` arguments must be integer or floating-point values
--> $DIR/type-check-2.rs:41:26
|
LL | asm!("{}", const 0 as *mut u8);
| ^^^^^^^^^^^^
error: asm `const` arguments must be integer or floating-point values
--> $DIR/type-check-2.rs:43:26
|
LL | asm!("{}", const &0);
| ^^
error: arguments for inline assembly must be copyable
--> $DIR/type-check-2.rs:66: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:78:28: 78:38]` for inline assembly
--> $DIR/type-check-2.rs:78: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 `std::vec::Vec<i32>` for inline assembly
--> $DIR/type-check-2.rs:80: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 a macro (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:82: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:84: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:92: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:95: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: asm `sym` operand must point to a fn or static
--> $DIR/type-check-2.rs:59:24
|
LL | asm!("{}", sym C);
| ^
error: asm `sym` operand must point to a fn or static
--> $DIR/type-check-2.rs:61:24
|
LL | asm!("{}", sym x);
| ^
error: argument 1 is required to be a constant
--> $DIR/type-check-2.rs:45:9
|
LL | asm!("{}", const x);
| ^^^^^^^^^^^^^^^^^^^^
error: argument 1 is required to be a constant
--> $DIR/type-check-2.rs:48:9
|
LL | asm!("{}", const const_foo(x));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: argument 1 is required to be a constant
--> $DIR/type-check-2.rs:51:9
|
LL | asm!("{}", const const_bar(x));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0381]: use of possibly-uninitialized variable: `x`
--> $DIR/type-check-2.rs:13:28
|
LL | asm!("{}", in(reg) x);
| ^ use of possibly-uninitialized `x`
error[E0381]: use of possibly-uninitialized variable: `y`
--> $DIR/type-check-2.rs:16:9
|
LL | asm!("{}", inout(reg) y);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y`
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
--> $DIR/type-check-2.rs:24: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.rs:26: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 18 previous errors
Some errors have detailed explanations: E0381, E0596.
For more information about an error, try `rustc --explain E0381`.

View file

@ -0,0 +1,71 @@
// only-x86_64
// compile-flags: -C target-feature=+avx512f
#![feature(asm)]
use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps};
fn main() {
unsafe {
// Types must be in the whitelist for 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 `std::arch::x86_64::__m128` cannot be used with this register class
asm!("{}", in(reg) _mm256_setzero_ps());
//~^ ERROR type `std::arch::x86_64::__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);
}
}

View file

@ -0,0 +1,118 @@
error: type `i128` cannot be used with this register class
--> $DIR/type-check-3.rs:12:28
|
LL | asm!("{}", in(reg) 0i128);
| ^^^^^
|
= note: register class `reg` supports these types: i16, i32, i64, f32, f64
error: type `std::arch::x86_64::__m128` cannot be used with this register class
--> $DIR/type-check-3.rs:14:28
|
LL | asm!("{}", in(reg) _mm_setzero_ps());
| ^^^^^^^^^^^^^^^^
|
= note: register class `reg` supports these types: i16, i32, i64, f32, f64
error: type `std::arch::x86_64::__m256` cannot be used with this register class
--> $DIR/type-check-3.rs:16: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:18: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:27: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:32: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:34: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:36: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:39: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:50: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:62: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:64: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:66: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

View file

@ -0,0 +1,23 @@
// only-x86_64
#![feature(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);
}
}

View file

@ -0,0 +1,26 @@
error[E0506]: cannot assign to `a` because it is borrowed
--> $DIR/type-check-4.rs:11: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:19: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`.

View file

@ -2,8 +2,9 @@
fn main() {
unsafe {
asm!(""); //~ ERROR inline assembly is not stable enough
//~^ WARN use of deprecated item 'asm'
llvm_asm!(""); //~ ERROR inline assembly is not stable enough
asm!("");
//~^ ERROR inline assembly is not stable enough
llvm_asm!("");
//~^ ERROR LLVM-style inline assembly will never be stabilized
}
}

View file

@ -4,10 +4,10 @@ error[E0658]: use of unstable library feature 'asm': inline assembly is not stab
LL | asm!("");
| ^^^
|
= note: see issue #70173 <https://github.com/rust-lang/rust/issues/70173> for more information
= note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
= help: add `#![feature(asm)]` to the crate attributes to enable
error[E0658]: use of unstable library feature 'llvm_asm': inline assembly is not stable enough for use and is subject to change
error[E0658]: use of unstable library feature 'llvm_asm': LLVM-style inline assembly will never be stabilized, prefer using asm! instead
--> $DIR/feature-gate-asm.rs:7:9
|
LL | llvm_asm!("");
@ -16,14 +16,6 @@ LL | llvm_asm!("");
= note: see issue #70173 <https://github.com/rust-lang/rust/issues/70173> for more information
= help: add `#![feature(llvm_asm)]` to the crate attributes to enable
warning: use of deprecated item 'asm': the syntax of asm! will change soon, use llvm_asm! to avoid breakage
--> $DIR/feature-gate-asm.rs:5:9
|
LL | asm!("");
| ^^^ help: replace the use of the deprecated item: `llvm_asm`
|
= note: `#[warn(deprecated)]` on by default
error: aborting due to 2 previous errors; 1 warning emitted
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -2,8 +2,9 @@
fn main() {
unsafe {
println!("{:?}", asm!("")); //~ ERROR inline assembly is not stable
//~^ WARN use of deprecated item 'asm'
println!("{:?}", llvm_asm!("")); //~ ERROR inline assembly is not stable
println!("{:?}", asm!(""));
//~^ ERROR inline assembly is not stable enough
println!("{:?}", llvm_asm!(""));
//~^ ERROR LLVM-style inline assembly will never be stabilized
}
}

View file

@ -4,10 +4,10 @@ error[E0658]: use of unstable library feature 'asm': inline assembly is not stab
LL | println!("{:?}", asm!(""));
| ^^^
|
= note: see issue #70173 <https://github.com/rust-lang/rust/issues/70173> for more information
= note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
= help: add `#![feature(asm)]` to the crate attributes to enable
error[E0658]: use of unstable library feature 'llvm_asm': inline assembly is not stable enough for use and is subject to change
error[E0658]: use of unstable library feature 'llvm_asm': LLVM-style inline assembly will never be stabilized, prefer using asm! instead
--> $DIR/feature-gate-asm2.rs:7:26
|
LL | println!("{:?}", llvm_asm!(""));
@ -16,14 +16,6 @@ LL | println!("{:?}", llvm_asm!(""));
= note: see issue #70173 <https://github.com/rust-lang/rust/issues/70173> for more information
= help: add `#![feature(llvm_asm)]` to the crate attributes to enable
warning: use of deprecated item 'asm': the syntax of asm! will change soon, use llvm_asm! to avoid breakage
--> $DIR/feature-gate-asm2.rs:5:26
|
LL | println!("{:?}", asm!(""));
| ^^^ help: replace the use of the deprecated item: `llvm_asm`
|
= note: `#[warn(deprecated)]` on by default
error: aborting due to 2 previous errors; 1 warning emitted
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -5,5 +5,5 @@ macro_rules! m {
}
macro_rules! n {
() => { unsafe { llvm_asm!(include_str!("file.txt")); } }
() => { unsafe { asm!(include_str!("file.txt")); } }
}

View file

@ -1,6 +1,6 @@
// ignore-emscripten no llvm_asm! support
// build-pass (FIXME(62277): could be check-pass?)
#![feature(llvm_asm)]
#![feature(asm)]
#![allow(unused)]
#[macro_use]

View file

@ -3,13 +3,14 @@
// test that errors in a (selection) of macros don't kill compilation
// immediately, so that we get more errors listed at a time.
#![feature(llvm_asm)]
#![feature(asm, llvm_asm)]
#![feature(trace_macros, concat_idents)]
#[derive(Default)] //~ ERROR
enum OrDeriveThis {}
fn main() {
asm!(invalid); //~ ERROR
llvm_asm!(invalid); //~ ERROR
concat_idents!("not", "idents"); //~ ERROR

View file

@ -6,44 +6,50 @@ LL | #[derive(Default)]
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: asm template must be a string literal
--> $DIR/macros-nonfatal-errors.rs:13:10
|
LL | asm!(invalid);
| ^^^^^^^
error: inline assembly must be a string literal
--> $DIR/macros-nonfatal-errors.rs:13:15
--> $DIR/macros-nonfatal-errors.rs:14:15
|
LL | llvm_asm!(invalid);
| ^^^^^^^
error: concat_idents! requires ident args.
--> $DIR/macros-nonfatal-errors.rs:15:5
--> $DIR/macros-nonfatal-errors.rs:16:5
|
LL | concat_idents!("not", "idents");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: argument must be a string literal
--> $DIR/macros-nonfatal-errors.rs:17:17
--> $DIR/macros-nonfatal-errors.rs:18:17
|
LL | option_env!(invalid);
| ^^^^^^^
error: expected string literal
--> $DIR/macros-nonfatal-errors.rs:18:10
--> $DIR/macros-nonfatal-errors.rs:19:10
|
LL | env!(invalid);
| ^^^^^^^
error: expected string literal
--> $DIR/macros-nonfatal-errors.rs:19:10
--> $DIR/macros-nonfatal-errors.rs:20:10
|
LL | env!(foo, abr, baz);
| ^^^
error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined
--> $DIR/macros-nonfatal-errors.rs:20:5
--> $DIR/macros-nonfatal-errors.rs:21:5
|
LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: format argument must be a string literal
--> $DIR/macros-nonfatal-errors.rs:22:13
--> $DIR/macros-nonfatal-errors.rs:23:13
|
LL | format!(invalid);
| ^^^^^^^
@ -54,19 +60,19 @@ LL | format!("{}", invalid);
| ^^^^^
error: argument must be a string literal
--> $DIR/macros-nonfatal-errors.rs:24:14
--> $DIR/macros-nonfatal-errors.rs:25:14
|
LL | include!(invalid);
| ^^^^^^^
error: argument must be a string literal
--> $DIR/macros-nonfatal-errors.rs:26:18
--> $DIR/macros-nonfatal-errors.rs:27:18
|
LL | include_str!(invalid);
| ^^^^^^^
error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2)
--> $DIR/macros-nonfatal-errors.rs:27:5
--> $DIR/macros-nonfatal-errors.rs:28:5
|
LL | include_str!("i'd be quite surprised if a file with this name existed");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -74,13 +80,13 @@ LL | include_str!("i'd be quite surprised if a file with this name existed")
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: argument must be a string literal
--> $DIR/macros-nonfatal-errors.rs:28:20
--> $DIR/macros-nonfatal-errors.rs:29:20
|
LL | include_bytes!(invalid);
| ^^^^^^^
error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2)
--> $DIR/macros-nonfatal-errors.rs:29:5
--> $DIR/macros-nonfatal-errors.rs:30:5
|
LL | include_bytes!("i'd be quite surprised if a file with this name existed");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -88,11 +94,11 @@ LL | include_bytes!("i'd be quite surprised if a file with this name existed
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: trace_macros! accepts only `true` or `false`
--> $DIR/macros-nonfatal-errors.rs:31:5
--> $DIR/macros-nonfatal-errors.rs:32:5
|
LL | trace_macros!(invalid);
| ^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 14 previous errors
error: aborting due to 15 previous errors
For more information about this error, try `rustc --explain E0665`.

View file

@ -25,6 +25,7 @@
// gate-test-movbe_target_feature
// gate-test-rtm_target_feature
// gate-test-f16c_target_feature
// gate-test-riscv_target_feature
#[target_feature(enable = "avx512bw")]
//~^ ERROR: currently unstable

View file

@ -1,5 +1,5 @@
error[E0658]: the target feature `avx512bw` is currently unstable
--> $DIR/gate.rs:29:18
--> $DIR/gate.rs:30:18
|
LL | #[target_feature(enable = "avx512bw")]
| ^^^^^^^^^^^^^^^^^^^