Implement `impl Trait` in return type position by anonymization.
This is the first step towards implementing `impl Trait` (cc #34511).
`impl Trait` types are only allowed in function and inherent method return types, and capture all named lifetime and type parameters, being invariant over them.
No lifetimes that are not explicitly named lifetime parameters are allowed to escape from the function body.
The exposed traits are only those listed explicitly, i.e. `Foo` and `Clone` in `impl Foo + Clone`, with the exception of "auto traits" (like `Send` or `Sync`) which "leak" the actual contents.
The implementation strategy is anonymization, i.e.:
```rust
fn foo<T>(xs: Vec<T>) -> impl Iterator<Item=impl FnOnce() -> T> {
xs.into_iter().map(|x| || x)
}
// is represented as:
type A</*invariant over*/ T> where A<T>: Iterator<Item=B<T>>;
type B</*invariant over*/ T> where B<T>: FnOnce() -> T;
fn foo<T>(xs: Vec<T>) -> A<T> {
xs.into_iter().map(|x| || x): $0 where $0: Iterator<Item=$1>, $1: FnOnce() -> T
}
```
`$0` and `$1` are resolved (to `iter::Map<vec::Iter<T>, closure>` and the closure, respectively) and assigned to `A` and `B`, after checking the body of `foo`. `A` and `B` are *never* resolved for user-facing type equality (typeck), but always for the low-level representation and specialization (trans).
The "auto traits" exception is implemented by collecting bounds like `impl Trait: Send` that have failed for the obscure `impl Trait` type (i.e. `A` or `B` above), pretending they succeeded within the function and trying them again after type-checking the whole crate, by replacing `impl Trait` with the real type.
While passing around values which have explicit lifetime parameters (of the function with `-> impl Trait`) in their type *should* work, regionck appears to assign inference variables in *way* too many cases, and never properly resolving them to either explicit lifetime parameters, or `'static`.
We might not be able to handle lifetime parameters in `impl Trait` without changes to lifetime inference, but type parameters can have arbitrary lifetimes in them from the caller, so most type-generic usecases (or not generic at all) should not run into this problem.
cc @rust-lang/lang
Commandline arguments influence whether incremental compilation
can use its compilation cache and thus their changes relative to
previous compilation sessions need to be taking into account. This
commit makes sure that one has to specify for every commandline
argument whether it influences incremental compilation or not.
Properly feature gate all unstable ABIs
Fixes https://github.com/rust-lang/rust/issues/34900
[breaking-change]
r? @pnkfelix
---
Function-visiting machinery for AST/HIR is surprisingly error-prone, it's *very* easy to miss some cases or visit something twice while writing a visitor. This is the true problem behind https://github.com/rust-lang/rust/issues/34900. I'll try to restructure these visitors a bit and send one more PR later.
Better attribute and metaitem encapsulation throughout the compiler
This PR refactors most (hopefully all?) of the `MetaItem` interactions outside of `libsyntax` (and a few inside) to interact with MetaItems through the provided traits instead of directly creating / destruct / matching against them. This is a necessary first step to eventually converting `MetaItem`s to internally use `TokenStream` representations (which will make `MetaItem` interactions much nicer for macro writers once the new macro system is in place).
r? @nrc
Enable reuse of `.o` files if nothing has changed
This PR completes a first "spike" for incremental compilation by enabling us to reuse `.o` files when nothing has changed. When in incr. mode, we will save `.o` files into the temporary directory, then copy them back out again if they are still valid. The code is still a bit rough but it does seem to work. =)
r? @michaelwoerister
Fixes#34036Fixes#34037Fixes#34038
macros: fix bug in `stmt` matchers
Today, `stmt` matchers stop too early when parsing expression statements that begin with non-braced macro invocations. For example,
```rust
fn main() {
macro_rules! m { ($s:stmt;) => { $s } }
id!(vec![].push(0););
//^ Before this PR, the `stmt` matcher only consumes "vec![]", so this is an error.
//| After this PR, the `stmt` matcher consumes "vec![].push(0)", so this compiles.
}
```
This change is backwards compatible due to the follow set for `stmt`.
r? @eddyb
Added tokenstream parser procedure
A tiny PR that simply adds a procedure for parsing `TokenStream`s to the parser in `src/libsyntax`. This is to ease using `TokenStream`s with the current (old) procedural macro system.
Simplify librustc_errors
This is part 2 of the error crate refactor, starting with #34403.
In this refactor, I focused on slimming down the error crate to fewer moving parts. As such, I've removed quite a few parts and replaced the with simpler, straight-line code. Specifically, this PR:
* Removes BasicEmitter
* Remove emit from emitter, leaving emit_struct
* Renames emit_struct to emit
* Removes CoreEmitter and focuses on a single Emitter
* Implements the latest changes to error format RFC (#1644)
* Removes (now-unused) code in emitter.rs and snippet.rs
* Moves more tests to the UI tester, removing some duplicate tests in the process
There is probably more that could be done with some additional refactoring, but this felt like it was getting to a good state.
r? @alexcrichton cc: @Manishearth (as there may be breaking changes in stuff I removed/changed)
Better error message for inner attribute following doc comment
Before it was always just "an inner attribute is not permitted in this context", whereas now we add a special case for when an inner attr follows an outer attr. If the outer attr is a doc comment, then the error is "an inner attr is not permitted following a doc comment", and otherwise it's "an inner attr is not permitted following an outer attribute". In all other cases it's still "an inner attribute is not permitted in this context".
Note that the public API and behaviour of `parse_attribute` is unchanged. Also, all new names are very open to bikeshedding -- they're arguably clunky.
Fixes#34516. cc @brson
Simplify the macro hygiene algorithm
This PR removes renaming from the hygiene algorithm and treats differently marked identifiers as unequal.
This change makes the scope of identifiers in `macro_rules!` items empty. That is, identifiers in `macro_rules!` definitions do not inherit any semantics from the `macro_rules!`'s scope.
Since `macro_rules!` macros are items, the scope of their identifiers "should" be the same as that of other items; in particular, the scope should contain only items. Since all items are unhygienic today, this would mean the scope should be empty.
However, the scope of an identifier in a `macro_rules!` statement today is the scope that the identifier would have if it replaced the `macro_rules!` (excluding anything unhygienic, i.e. locals only).
To continue to support this, this PR tracks the scope of each `macro_rules!` and uses it in `resolve` to ensure that an identifier expanded from a `macro_rules!` gets a chance to resolve to the locals in the `macro_rules!`'s scope.
This PR is a pure refactoring. After this PR,
- `syntax::ext::expand` is much simpler.
- We can expand macros in any order without causing problems for hygiene (needed for macro modularization).
- We can deprecate or remove today's `macro_rules!` scope easily.
- Expansion performance improves by 25%, post-expansion memory usage decreases by ~5%.
- Expanding a block is no longer quadratic in the number of `let` statements (fixes#10607).
r? @nrc
Fix bugs in macro-expanded statement parsing
Fixes#34543.
This is a [breaking-change]. For example, the following would break:
```rust
macro_rules! m { () => {
println!("") println!("")
//^ Semicolons are now required on macro-expanded non-braced macro invocations
//| in statement positions.
let x = 0
//^ Semicolons are now required on macro-expanded `let` statements
//| that are followed by more statements, so this would break.
let y = 0 //< (this would still be allowed to reduce breakage in the wild)
}
fn main() { m!() }
```
r? @eddyb
```rust
macro_rules! m { () => { let x = 1; x } }
macro_rules! n { () => {
m!() //< This can now expand into statements
}}
fn main() { n!(); }
```
and revert needless fallout fixes.
Fix expansion performance regression
**syntax-[breaking-change] cc #31645**
This fixes#34630 by reverting commit 5bf7970 of PR #33943, which landed in #34424.
By removing the `Rc<_>` wrapping around `Delimited` and `SequenceRepetition` in `TokenTree`, 5bf7970 made cloning `TokenTree`s more expensive. While this had no measurable performance impact on the compiler's crates, it caused an order of magnitude performance regression on some macro-heavy code in the wild. I believe this is due to clones of `TokenTree`s in `macro_parser.rs` and/or `macro_rules.rs`.
r? @nrc
Support `cfg_attr` on `path` attributes
Fixes#25544.
This is technically a [breaking-change]. For example, the following would break:
```rust
mod foo; // Suppose `foo.rs` existed in the appropriate location
```
Identify when documetation comments have been missplaced in the
following places:
* After a struct element:
```rust
// file.rs:
struct X {
a: u8 /** document a */,
}
```
```bash
$ rustc file.rs
file.rs:2:11: 2:28 error: found documentation comment that doesn't
document anything
file.rs:2 a: u8 /** document a */,
^~~~~~~~~~~~~~~~~
file.rs:2:11: 2:28 help: doc comments must come before what they document,
maybe a comment was intended with `//`?
```
* As the last line of a struct:
```rust
// file.rs:
struct X {
a: u8,
/// incorrect documentation
}
```
```bash
$ rustc file.rs
file.rs:3:5: 3:27 error: found a documentation comment that doesn't
document anything
file.rs:3 /// incorrect documentation
^~~~~~~~~~~~~~~~~~~~~~
file.rs:3:5: 3:27 help: doc comments must come before what they document,
maybe a comment was intended with `//`?
```
* As the last line of a `fn`:
```rust
// file.rs:
fn main() {
let x = 1;
/// incorrect documentation
}
```
```bash
$ rustc file.rs
file.rs:3:5: 3:27 error: found a documentation comment that doesn't
document anything
file.rs:3 /// incorrect documentation
^~~~~~~~~~~~~~~~~~~~~~
file.rs:3:5: 3:27 help: doc comments must come before what they document,
maybe a comment was intended with `//`?
```
Fix#27429, #30322
This is a spiritual succesor to #34268/8531d581, in which we replaced a
number of matches of None to the unit value with `if let` conditionals
where it was judged that this made for clearer/simpler code (as would be
recommended by Manishearth/rust-clippy's `single_match` lint). The same
rationale applies to matches of None to the empty block.
Forbid type parameters and global paths in macro invocations
Fixes#28558.
This is a [breaking-change]. For example, the following would break:
```rust
macro_rules! m { () => { () } }
fn main() {
m::<T>!(); // Type parameters are no longer allowed in macro invocations
::m!(); // Global paths are no longer allowed in macro invocations
}
```
Any breakage can be fixed by removing the type parameters or the leading `::` (respectively).
r? @eddyb