Initially MIR differentiated between arguments and locals, which
introduced a need to add extra copies assigning the argument to a
local, even for simple bindings. This differentiation no longer exists,
but we're still creating those copies, bloating the MIR and LLVM IR we
emit.
Additionally, the current approach means that we create debug info for
both the incoming argument (marking it as an argument), and then
immediately shadow it a local that goes by the same name. This can be
confusing when using e.g. "info args" in gdb, or when e.g. a debugger
with a GUI displays the function arguments separately from the local
variables, especially when the binding is mutable, because the argument
doesn't change, while the local variable does.
This commit moves the calculation of the `LanguageItems` structure into a
query rather than being calculated before the `TyCtxt` exists, with the eventual
end goal of removing some `CrateStore` methods.
Operand: 72 -> 24 B
Statement: 192 -> 96 B
Terminator: 256 -> 112 B
librustc translation memory usage: 1795 -> 1669 MB
next step would be interning lvalues, I suppose?
This removes another special case of Switch by replacing it with the more general SwitchInt. While
this is more clunky currently, there’s no reason we can’t make it nice (and efficient) to use.
[MIR] track Location in MirVisitor, combine Location
All the users of MirVisitor::visit_statement implement their own statement index tracking. This PR move the tracking into MirVisitor itself.
Also, there were 2 separate implementations of Location that were identical. This PR eliminates one of them.
Implement the `!` type
This implements the never type (`!`) and hides it behind the feature gate `#[feature(never_type)]`. With the feature gate off, things should build as normal (although some error messages may be different). With the gate on, `!` is usable as a type and diverging type variables (ie. types that are unconstrained by anything in the code) will default to `!` instead of `()`.
Use it instead of a `panic` for inexhaustive matches and correct the
comment. I think we trust our match-generation algorithm enough to
generate these blocks, and not generating an `unreachable` means that
LLVM won't optimize `match void() {}` to an `unreachable`.
MSVC requires unwinding code to be split to a tree of *funclets*, where each funclet
can only branch to itself or to to its parent.
Luckily, the code we generates matches this pattern. Recover that structure in
an analyze pass and translate according to that.
Primarily affects the MIR construction, which indirectly improves LLVM
IR generation, but some LLVM IR changes have been made too.
* Handle "statement expressions" more intelligently. These are
expressions that always evaluate to `()`. Previously a temporary would
be generated as a destination to translate into, which is unnecessary.
This affects assignment, augmented assignment, `return`, `break` and
`continue`.
* Avoid inserting drops for non-drop types in more places. Scheduled
drops were already skipped for types that we knew wouldn't need
dropping at construction time. However manually-inserted drops like
those for `x` in `x = y;` were still generated. `build_drop` now takes
a type parameter like its `schedule_drop` counterpart and checks to
see if the type needs dropping.
* Avoid generating an extra temporary for an assignment where the types
involved don't need dropping. Previously an expression like
`a = b + 1;` would result in a temporary for `b + 1`. This is so the
RHS can be evaluated, then the LHS evaluated and dropped and have
everything work correctly. However, this isn't necessary if the `LHS`
doesn't need a drop, as we can just overwrite the existing value.
* Improves lvalue analysis to allow treating an `Rvalue::Use` as an
operand in certain conditions. The reason for it never being an
operand is so it can be zeroed/drop-filled, but this is only true for
types that need dropping.
The first two changes result in significantly fewer MIR blocks being
generated, as previously almost every statement would end up generating
a new block due to the drop of the `()` temporary being generated.
Some types weren't being properly monomorphised, and didn't have their
regions properly erased. This is now fixed.
Also fixes an issue where a temp was initialized in two separate
branches, but wasn't given an alloca.