This PR refactors away `Module`'s `external_module_children` and instead puts `extern crate` declarations in `children` like other items, simplifying duplicate checking and name resolution.
This PR also allows values to share a name with extern crates, which are only defined in the type namespace. Other than that, it is a pure refactoring.
r? @nrc
This is a PR for #21195. It changes the way unspecified `help` and `ǹote` messages are handled in compile-fail tests as suggested by @oli-obk in the issue: if there are some `note` or `help` annotations, there must be annotations for all `help` or `note` messages of this test. Maybe it makes also sense to add an option to specify that the this test should fail if there are unspecified `help` or `note` messages.
With this change, the following tests fail:
[compile-fail] compile-fail/changing-crates.rs
[compile-fail] compile-fail/default_ty_param_conflict_cross_crate.rs
[compile-fail] compile-fail/lifetime-inference-give-expl-lifetime-param.rs
[compile-fail] compile-fail/privacy1.rs
[compile-fail] compile-fail/svh-change-lit.rs
[compile-fail] compile-fail/svh-change-significant-cfg.rs
[compile-fail] compile-fail/svh-change-trait-bound.rs
[compile-fail] compile-fail/svh-change-type-arg.rs
[compile-fail] compile-fail/svh-change-type-ret.rs
[compile-fail] compile-fail/svh-change-type-static.rs
[compile-fail] compile-fail/svh-use-trait.rs
I'll add the missing annotations if we decide to accept this change.
the previous code generated a temporary of the inner type and assigned the box-memory to it. So if you did `let x: Box<usize> = box 5;` you got a
```rust
let var0: Box<usize>; // x
let mut tmp0: Box<usize>;
let mut tmp1: usize;
...
tmp1 = Box(usize);
(*tmp1) = const 5;
tmp0 = tmp1;
var0 = tmp0;
```
r? @nagisa
I don't believe these test cases have served any purpose in years.
The shootout benchmarks are now upstreamed. A new benchmark suite
should rather be maintained out of tree.
r? @nikomatsakis
These commits perform a few high-level changes with the goal of enabling i686 MSVC unwinding:
* LLVM is upgraded to pick up the new exception handling instructions and intrinsics for MSVC. This puts us somewhere along the 3.8 branch, but we should still be compatible with LLVM 3.7 for non-MSVC targets.
* All unwinding for MSVC targets (both 32 and 64-bit) are implemented in terms of this new LLVM support. I would like to also extend this to Windows GNU targets to drop the runtime dependencies we have on MinGW, but I'd like to land this first.
* Some tests were fixed up for i686 MSVC here and there where necessary. The full test suite should be passing now for that target.
In terms of landing this I plan to have this go through first, then verify that i686 MSVC works, then I'll enable `make check` on the bots for that target instead of just `make` as-is today.
Closes#25869
This brings some routine upgrades to the bundled LLVM that we're using, the most
notable of which is a bug fix to the way we handle range asserts when loading
the discriminant of an enum. This fix ended up being very similar to f9d4149c
where we basically can't have a range assert when loading a discriminant due to
filling drop, and appropriate flags were added to communicate this to
`trans::adt`.
I don't believe these test cases have served any purpose in years.
The shootout benchmarks are now upstreamed. A new benchmark suite
should rather be maintained out of tree.
This fixes an ICE introduced by #31065 that occurs when a path cannot be resolved because of a certain class of unresolved import (`Indeterminate` imports).
For example, this currently causes an ICE:
```rust
mod foo { pub use self::*; }
fn main() { foo::f() }
```
r? @nrc
We no longer require `use` and `extern crate` items to precede other items in modules thanks to [RFC #385](https://github.com/rust-lang/rfcs/pull/385), but we still require `use` and `extern crate` items to precede statements in blocks (other items can appear anywhere in a block).
I think that this is a needless distinction between imports and other items that contradicts the intent of the RFC.
If the tests were run with `RUST_BACKTRACE=1 make check` this test failed. If they were run without it it succeeded.
We need to use `env_remove` instead of `env_clear` because the latter will never work on windows
The purpose of the translation item collector is to find all monomorphic instances of functions, methods and statics that need to be translated into LLVM IR in order to compile the current crate.
So far these instances have been discovered lazily during the trans path. For incremental compilation we want to know the set of these instances in advance, and that is what the trans::collect module provides.
In the future, incremental and regular translation will be driven by the collector implemented here.
r? @nikomatsakis
cc @rust-lang/compiler
Translation Item Collection
===========================
This module is responsible for discovering all items that will contribute to
to code generation of the crate. The important part here is that it not only
needs to find syntax-level items (functions, structs, etc) but also all
their monomorphized instantiations. Every non-generic, non-const function
maps to one LLVM artifact. Every generic function can produce
from zero to N artifacts, depending on the sets of type arguments it
is instantiated with.
This also applies to generic items from other crates: A generic definition
in crate X might produce monomorphizations that are compiled into crate Y.
We also have to collect these here.
The following kinds of "translation items" are handled here:
- Functions
- Methods
- Closures
- Statics
- Drop glue
The following things also result in LLVM artifacts, but are not collected
here, since we instantiate them locally on demand when needed in a given
codegen unit:
- Constants
- Vtables
- Object Shims
General Algorithm
-----------------
Let's define some terms first:
- A "translation item" is something that results in a function or global in
the LLVM IR of a codegen unit. Translation items do not stand on their
own, they can reference other translation items. For example, if function
`foo()` calls function `bar()` then the translation item for `foo()`
references the translation item for function `bar()`. In general, the
definition for translation item A referencing a translation item B is that
the LLVM artifact produced for A references the LLVM artifact produced
for B.
- Translation items and the references between them for a directed graph,
where the translation items are the nodes and references form the edges.
Let's call this graph the "translation item graph".
- The translation item graph for a program contains all translation items
that are needed in order to produce the complete LLVM IR of the program.
The purpose of the algorithm implemented in this module is to build the
translation item graph for the current crate. It runs in two phases:
1. Discover the roots of the graph by traversing the HIR of the crate.
2. Starting from the roots, find neighboring nodes by inspecting the MIR
representation of the item corresponding to a given node, until no more
new nodes are found.
The roots of the translation item graph correspond to the non-generic
syntactic items in the source code. We find them by walking the HIR of the
crate, and whenever we hit upon a function, method, or static item, we
create a translation item consisting of the items DefId and, since we only
consider non-generic items, an empty type-substitution set.
Given a translation item node, we can discover neighbors by inspecting its
MIR. We walk the MIR and any time we hit upon something that signifies a
reference to another translation item, we have found a neighbor. Since the
translation item we are currently at is always monomorphic, we also know the
concrete type arguments of its neighbors, and so all neighbors again will be
monomorphic. The specific forms a reference to a neighboring node can take
in MIR are quite diverse. Here is an overview:
The most obvious form of one translation item referencing another is a
function or method call (represented by a CALL terminator in MIR). But
calls are not the only thing that might introduce a reference between two
function translation items, and as we will see below, they are just a
specialized of the form described next, and consequently will don't get any
special treatment in the algorithm.
A function does not need to actually be called in order to be a neighbor of
another function. It suffices to just take a reference in order to introduce
an edge. Consider the following example:
```rust
fn print_val<T: Display>(x: T) {
println!("{}", x);
}
fn call_fn(f: &Fn(i32), x: i32) {
f(x);
}
fn main() {
let print_i32 = print_val::<i32>;
call_fn(&print_i32, 0);
}
```
The MIR of none of these functions will contain an explicit call to
`print_val::<i32>`. Nonetheless, in order to translate this program, we need
an instance of this function. Thus, whenever we encounter a function or
method in operand position, we treat it as a neighbor of the current
translation item. Calls are just a special case of that.
In a way, closures are a simple case. Since every closure object needs to be
constructed somewhere, we can reliably discover them by observing
`RValue::Aggregate` expressions with `AggregateKind::Closure`. This is also
true for closures inlined from other crates.
Drop glue translation items are introduced by MIR drop-statements. The
generated translation item will again have drop-glue item neighbors if the
type to be dropped contains nested values that also need to be dropped. It
might also have a function item neighbor for the explicit `Drop::drop`
implementation of its type.
A subtle way of introducing neighbor edges is by casting to a trait object.
Since the resulting fat-pointer contains a reference to a vtable, we need to
instantiate all object-save methods of the trait, as we need to store
pointers to these functions even if they never get called anywhere. This can
be seen as a special case of taking a function reference.
Since `Box` expression have special compiler support, no explicit calls to
`exchange_malloc()` and `exchange_free()` may show up in MIR, even if the
compiler will generate them. We have to observe `Rvalue::Box` expressions
and Box-typed drop-statements for that purpose.
Interaction with Cross-Crate Inlining
-------------------------------------
The binary of a crate will not only contain machine code for the items
defined in the source code of that crate. It will also contain monomorphic
instantiations of any extern generic functions and of functions marked with
The collection algorithm handles this more or less transparently. When
constructing a neighbor node for an item, the algorithm will always call
`inline::get_local_instance()` before proceeding. If no local instance can
be acquired (e.g. for a function that is just linked to) no node is created;
which is exactly what we want, since no machine code should be generated in
the current crate for such an item. On the other hand, if we can
successfully inline the function, we subsequently can just treat it like a
local item, walking it's MIR et cetera.
Eager and Lazy Collection Mode
------------------------------
Translation item collection can be performed in one of two modes:
- Lazy mode means that items will only be instantiated when actually
referenced. The goal is to produce the least amount of machine code
possible.
- Eager mode is meant to be used in conjunction with incremental compilation
where a stable set of translation items is more important than a minimal
one. Thus, eager mode will instantiate drop-glue for every drop-able type
in the crate, even of no drop call for that type exists (yet). It will
also instantiate default implementations of trait methods, something that
otherwise is only done on demand.
Open Issues
-----------
Some things are not yet fully implemented in the current version of this
module.
Since no MIR is constructed yet for initializer expressions of constants and
statics we cannot inspect these properly.
Ideally, no translation item should be generated for const fns unless there
is a call to them that cannot be evaluated at compile time. At the moment
this is not implemented however: a translation item will be produced
regardless of whether it is actually needed or not.
<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/rust-lang/rust/30900)
<!-- Reviewable:end -->
This is a work in progress PR that potentially should fix#29084, #28308, #25385, #28288, #31011. I think this may also adresse parts of #2887.
The problem in this issues seems to be that when transcribing macro arguments, we just clone the argument Nonterminal, which still has to original spans. This leads to the unprintable spans. One solution would be to update the spans of the inserted argument to match the argument in the macro definition. So for [this testcase](https://github.com/rust-lang/rust/compare/master...fhahn:macro-ice?expand=1#diff-f7def7420c51621640707b6337726876R2) the error message would be displayed in the macro definition:
src/test/compile-fail/issue-31011.rs:4:12: 4:22 error: attempted access of field `trace` on type `&T`, but no field with that name was found
src/test/compile-fail/issue-31011.rs:4 if $ctx.trace {
Currently I've added a very simple `update_span` function, which updates the span of the outer-most expression of a `NtExpr`, but this `update_span` function should be updated to handle all Nonterminals. But I'm pretty new to the macro system and would like to check if this approach makes sense, before doing that.
This splits the output of panics into two lines as proposed in #15239 and adds a
note about how to get a backtrace. Because the default panic message consists of
multiple lines now, this changes the test runner's failure output to not indent
the first line anymore.
Fixes#15239 and fixes#11704.
The purpose of the translation item collector is to find all monomorphic instances of functions, methods and statics that need to be translated into LLVM IR in order to compile the current crate.
So far these instances have been discovered lazily during the trans path. For incremental compilation we want to know the set of these instances in advance, and that is what the trans::collect module provides.
In the future, incremental and regular translation will be driven by the collector implemented here.
On all platforms, reading from stdin where the actual stdin isn't present should
return 0 bytes as having been read rather than the entire buffer.
On Windows, handle the case where we're inheriting stdio handles but one of them
isn't present. Currently the behavior is to fail returning an I/O error but
instead this commit corrects it to detecting this situation and propagating the
non-set handle.
Closes#31167
This fixes#23880, a scoping bug in which items in a block are shadowed by local variables and type parameters that are in scope.
After this PR, an item in a block will shadow any local variables or type parameters above the item in the scope hierarchy. Items in a block will continue to be shadowed by local variables in the same block (even if the item is defined after the local variable).
This is a [breaking-change]. For example, the following code breaks:
```rust
fn foo() {
let mut f = 1;
{
fn f() {}
f += 1; // This will resolve to the function instead of the local variable
}
}
The goal is that the compiler will pass `Result`s around rather than using abort_if_errors. To preserve behaviour we currently abort at the top level. I've removed all other aborts from the driver, but haven't touched any of the nested aborts.
This fixes a bug in which items in a block are shadowed by local variables and type parameters that are in scope.
It is a [breaking-change]. For example, the following code breaks:
```rust
fn foo() {
let mut f = 1;
{
fn f() {}
f += 1; // This will now resolve to the function instead of the local variable
}
}
```
Any breakage can be fixed by renaming the item that is no longer shadowed.
On all platforms, reading from stdin where the actual stdin isn't present should
return 0 bytes as having been read rather than the entire buffer.
On Windows, handle the case where we're inheriting stdio handles but one of them
isn't present. Currently the behavior is to fail returning an I/O error but
instead this commit corrects it to detecting this situation and propagating the
non-set handle.
Closes#31167
This PR adds some minor error correction to the parser - if there is a missing ident, we recover and carry on. It also makes compilation more robust so that non-fatal errors (which is still most of them, unfortunately) in parsing do not cause us to abort compilation. The effect is that a program with a missing or incorrect ident can get all the way to type checking.