Optimize the parser's last token handling.
The parser currently makes a heap copy of the last token in four cases:
identifiers, paths, doc comments, and commas. The identifier and
interpolation cases are unused, and for doc comments and commas we only
need to record their presence, not their value.
This commit consolidates the last token handling and avoids the
unnecessary copies by replacing `last_token`, `last_token_eof`, and
`last_token_interpolated` with a new field `last_token_kind`. This
simplifies the parser slightly and speeds up parsing on some files by
3--4%.
Avoid loading and parsing unconfigured non-inline modules.
For example, `#[cfg(any())] mod foo;` will always compile after this PR, even if `foo.rs` and `foo/mod.rs` do not exist or do not contain valid Rust.
Fixes#36478 and fixes#27873.
r? @nrc
The parser currently makes a heap copy of the last token in four cases:
identifiers, paths, doc comments, and commas. The identifier and
interpolation cases are unused, and for doc comments and commas we only
need to record their presence, not their value.
This commit consolidates the last token handling and avoids the
unnecessary copies by replacing `last_token`, `last_token_eof`, and
`last_token_interpolated` with a new field `last_token_kind`. This
simplifies the parser slightly and speeds up parsing on some files by
3--4%.
Refactor `PathListItem`s
This refactors away variant `Mod` of `ast::PathListItemKind` and refactors the remaining variant `Ident` to a struct `ast::PathListItem_`.
We want to catch this error:
```
if (foo)
bar;
```
as it's valid syntax in other languages, and say how to fix it.
Unfortunately it didn't care if the suggestion made sense and just
highlighted the unexpected token.
Now it attempts to parse a statement, and if it succeeds, it shows the
help message.
Fixes#35907
Specific error message for missplaced doc comments
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
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 `()`.
```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.
To allow these braced macro invocation, this PR removes the optional expression from `ast::Block` and instead uses a `StmtKind::Expr` at the end of the statement list.
Currently, braced macro invocations in blocks can expand into statements (and items) except when they are last in a block, in which case they can only expand into expressions.
For example,
```rust
macro_rules! make_stmt {
() => { let x = 0; }
}
fn f() {
make_stmt! {} //< This is OK...
let x = 0; //< ... unless this line is commented out.
}
```
Fixes#34418.