summary refs log tree commit diff
path: root/src/test/ui/macros
AgeCommit message (Collapse)AuthorLines
2020-05-26expand `env!` with def-site contextAndy Russell-0/+2
2020-05-19Auto merge of #69171 - Amanieu:new-asm, r=nagisa,nikomatsakisbors-17/+24
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`.
2020-05-19Auto merge of #68717 - petrochenkov:stabexpat, r=varkorbors-1/+1
Stabilize fn-like proc macros in expression, pattern and statement positions I.e. all the positions in which stable `macro_rules` macros are supported. Depends on https://github.com/rust-lang/rust/pull/68716 ("Stabilize `Span::mixed_site`"). cc https://github.com/rust-lang/rust/issues/54727 cc https://github.com/rust-lang/rust/issues/54727#issuecomment-580647446 Stabilization report: https://github.com/rust-lang/rust/pull/68717#issuecomment-623197503.
2020-05-18Add tests for asm!Amanieu d'Antras-17/+24
2020-05-09Rollup merge of #71185 - JohnTitor:run-fail, r=petrochenkovRalf Jung-0/+113
Move tests from `test/run-fail` to UI Fixes #65440 cc #65865 #65506 r? @nikomatsakis
2020-05-08Skip tests on emscriptenYuki Okushi-0/+15
2020-05-07reword "possible candidate" import suggestionAndy Russell-1/+1
2020-05-06Move tests from `test/run-fail` to UIYuki Okushi-0/+98
2020-05-03Stabilize fn-like proc macros in expression, pattern and statement positionsVadim Petrochenkov-1/+1
2020-05-01Add new tests and bless old testsLeSeulArtichaut-3/+7
2020-04-30Rollup merge of #71205 - NeoRaider:check_attr, r=jonas-schievinkDylan DPC-5/+3
rustc: fix check_attr() for methods, closures and foreign functions This fixes an issue that previously turned up for methods in https://github.com/rust-lang/rust/pull/69274, but also exists for closures and foreign function: `check_attr` does not call `codegen_fn_attrs()` for these types when it should, meaning that incorrectly used function attributes are not diagnosed without codegen. The issue affects our UI tests, as they run with `--emit=metadata` by default, but as it turns out, this is not the only case: Function attributes are not checked on any dead code without this fix! This makes the fix a **breaking change**. The following very silly Rust programs compiles fine on stable Rust when it should not, which is fixed by this PR. ```rust fn main() { #[target_feature(enable = "sse2")] || {}; } ``` I assume any real-world program which may trigger this issue would at least emit a dead code warning, but of course that is no guarantee that such code does not exist... Fixes #70307
2020-04-23Moving more build-pass tests to check-passVal Markovic-1/+1
One or two tests became build-pass without the FIXME because they really needed build-pass (were failing without it). Helps with #62277
2020-04-16rustc: fix check_attr() for methods, closures and foreign functionsMatthias Schiffer-5/+3
UI tests are updated with additional error messages that were missing before.
2020-04-11rustc: Add a warning count upon completionRoccoDev-1/+9
2020-04-04macro_rules: `NtLifetime` cannot start with an identifierVadim Petrochenkov-0/+13
2020-04-02tests: remove ignore directives from tests that mention core/alloc/std spans.Eduard-Mihai Burtescu-16/+3
2020-03-27Rollup merge of #70434 - Centril:fix-34421, r=estebankMazdak Farrokhzad-0/+55
suggest `;` on expr `mac!()` which is good as stmt `mac!()` Fixes https://github.com/rust-lang/rust/issues/34421 by implementing @jseyfried's suggestion in https://github.com/rust-lang/rust/issues/34421#issuecomment-301578683. r? @petrochenkov
2020-03-27suggest semi on expr mac!() good as stmt mac!().Mazdak Farrokhzad-0/+55
2020-03-26Update tests to use llvm_asm!Amanieu d'Antras-8/+8
2020-03-24fix rebase fallout due to #69497.Mazdak Farrokhzad-10/+25
2020-03-24defatalize `compile_declarative_macro`Mazdak Farrokhzad-0/+22
2020-03-24mbe::transcribe: defatalize errors.Mazdak Farrokhzad-4/+33
2020-03-24generic_extension: defatalize Error caseMazdak Farrokhzad-5/+22
2020-03-24nix panictry! in ParserAnyMacro::makeMazdak Farrokhzad-1/+27
2020-03-23Rollup merge of #69942 - estebank:sized-verbose-sugg, r=matthewjasperMazdak Farrokhzad-1/+1
Increase verbosity when suggesting subtle code changes Do not suggest changes that are actually quite small inline, to minimize the likelihood of confusion. Fix #69243.
2020-03-23Rollup merge of #70227 - LeSeulArtichaut:typo-def, r=CentrilMazdak Farrokhzad-6/+4
Only display definition when suggesting a typo Closes #70206 r? @Centril
2020-03-22Normalize wording of privacy access labelsEsteban Küber-1/+1
2020-03-21Bless testsLeSeulArtichaut-6/+4
2020-03-21Rollup merge of #69497 - Zoxc:ast-fragment-error, r=petrochenkovDylan DPC-2/+13
Don't unwind when hitting the macro expansion recursion limit This removes one use of `FatalError.raise()`. r? @petrochenkov
2020-03-20expand_include: set `.directory` to dir of included file.Mazdak Farrokhzad-0/+13
2020-03-19Update testJohn Kåre Alsaker-2/+13
2020-03-17Update pretty testsGuillaume Gomez-1/+1
2020-03-13Auto merge of #67502 - Mark-Simulacrum:opt-catch, r=Mark-Simulacrumbors-18/+17
Optimize catch_unwind to match C++ try/catch This refactors the implementation of catching unwinds to allow LLVM to inline the "try" closure directly into the happy path, avoiding indirection. This means that the catch_unwind implementation is (after this PR) zero-cost unless a panic is thrown. https://rust.godbolt.org/z/cZcUSB is an example of the current codegen in a simple case. Notably, the codegen is *exactly the same* if `-Cpanic=abort` is passed, which is clearly not great. This PR, on the other hand, generates the following assembly: ```asm # -Cpanic=unwind: push rbx mov ebx,0x2a call QWORD PTR [rip+0x1c53c] # <happy> mov eax,ebx pop rbx ret mov rdi,rax call QWORD PTR [rip+0x1c537] # cleanup function call call QWORD PTR [rip+0x1c539] # <unfortunate> mov ebx,0xd mov eax,ebx pop rbx ret # -Cpanic=abort: push rax call QWORD PTR [rip+0x20a1] # <happy> mov eax,0x2a pop rcx ret ``` Fixes #64224, and resolves #64222.
2020-03-13Add test for issue-58490Yuki Okushi-0/+40
2020-03-10macros/unknown-builtin: use hack for musl problemsMazdak Farrokhzad-1/+6
2020-03-10--bless some testsMazdak Farrokhzad-3/+7
2020-03-06Turn trailing tokens in `assert!()` into hard errorsLeSeulArtichaut-13/+7
2020-03-05Remove eh_unwind_resume lang itemAmanieu d'Antras-18/+17
2020-02-24parse: use `parse_item_common` in `parse_foreign_item`.Mazdak Farrokhzad-9/+10
2020-02-15fuse extern & associated item parsing up to defaultnessMazdak Farrokhzad-3/+3
2020-02-15Avoid calling `fn_sig` on closuresYuki Okushi-0/+40
2020-02-13parser: misc small item related improvements & cleanups.Mazdak Farrokhzad-10/+9
2020-02-06rustc_macros: don't limit the -Zmacro-backtrace suggestion to extern macros.Eduard-Mihai Burtescu-4/+64
2020-02-06rustc_errors: hide "in this macro invocation" when redundant, more explicitly.Eduard-Mihai Burtescu-4/+1
2020-02-06rustc: rename -Zexternal-macro-backtrace to -Zmacro-backtrace.Eduard-Mihai Burtescu-4/+4
2020-02-06Rollup merge of #68788 - Centril:unified-fn-bodies, r=petrochenkovDylan DPC-2/+2
Towards unified `fn` grammar Part of https://github.com/rust-lang/rust/pull/68728. - Syntactically, `fn` items in `extern { ... }` blocks can now have bodies (`fn foo() { ... }` as opposed to `fn foo();`). As above, we use semantic restrictions instead. - Syntactically, `fn` items in free contexts (directly in a file or a module) can now be without bodies (`fn foo();` as opposed to `fn foo() { ... }`. As above, we use semantic restrictions instead, including for non-ident parameter patterns. - We move towards unifying the `fn` front matter; this is fully realized in https://github.com/rust-lang/rust/pull/68728. r? @petrochenkov
2020-02-05`#![recursion_limit = "X"]`: note current crate name.Mazdak Farrokhzad-1/+1
2020-02-05parser: merge `fn` grammars wrt. bodies & headersMazdak Farrokhzad-2/+2
also refactor `FnKind` and `visit_assoc_item` visitors
2020-01-31Auto merge of #68080 - varkor:declared-here, r=petrochenkovbors-5/+5
Address inconsistency in using "is" with "declared here" "is" was generally used for NLL diagnostics, but not other diagnostics. Using "is" makes the diagnostics sound more natural and readable, so it seems sensible to commit to them throughout. r? @Centril
2020-01-26rustc_span: move pretty syntax from macro_backtrace to ExpnKind::descr.Eduard-Mihai Burtescu-1/+1