Consider a "backend" non-macro form for `asm!`
Opened this issue · 4 comments
Macros expanding directly into internal compiler structures (AST) are rather an exception in rustc than a rule.
The compiler frontend is in a process of migration to a token-based model (inspired by proc macros) where each macro expands to some actual non-macro syntax (token stream).
For inline assembly the surface syntax of that non-macro representation is not important right now, except that it should be unambiguous in the expression position, like extern break box { ... } or whatever.
It can probably be wordy or unwieldy to write manually, but not necessarily.
What's important in my opinion is ability to lower different surface asm syntaxes into this common non-macro representation.
Basically, if you are bikeshedding some asm!(syntax1) vs asm!(syntax2) alternative, make sure that both can be converted into a common non-macro form, so that the asm!(syntax2) alternative could always be implemented just as a different proc macro my_asm!(syntax2).
Ideally we would just use asm directly, but it isn't a reserved keyword so it would be a breaking change. My thought was to use asm! for now until the next edition, where we would switch to an asm keyword.
In the meantime, I think extern asm/extern llvm_asm would work as an internal (unstable) form that the macro expands into.
I think lowering it as a lang_item type that impl the Fn traits when well-formed would be best. This way most of the compiler treat it like any other type, only the macro, codegen, and whatever creates the Fn impls will have to treat it special.
The main inspiration for this is how LLVM store inline asm in call statements (if you compare it to the LLVM-IR it will look very similar).
Backends that use the shim wouldn't even need the this type, just call the extern "C" function directly.
Unfortunately it's not as simple as that: there are quite a few verifications and transformations that the compiler needs to perform during type checking that are specific to asm!, which means that we can't just defer everything until codegen.
You can have a look at my WIP implementation to see the kind of checks and transformations that are needed: rust-lang/rust#69171
That's what I meant by well-formed, I was not suggesting delaying any checks to codegen.
The idea is just to hide it in a call so most of the compiler doesn't have to care about it, but any part that needs/wants to can.