Prevent impossible combinations in `ast::ModKind`.
`ModKind::Loaded` has an `inline` field and a `had_parse_error` field. If the `inline` field is `Inline::Yes` then `had_parse_error` must be `Ok(())`.
This commit moves the `had_parse_error` field into the `Inline::No` variant. This makes it impossible to create the nonsensical combination of `inline == Inline::Yes` and `had_parse_error = Err(_)`.
r? ```@Urgau```
`ModKind::Loaded` has an `inline` field and a `had_parse_error` field.
If the `inline` field is `Inline::Yes` then `had_parse_error` must be
`Ok(())`.
This commit moves the `had_parse_error` field into the `Inline::No`
variant. This makes it impossible to create the nonsensical combination
of `inline == Inline::Yes` and `had_parse_error = Err(_)`.
```
error: cannot find attribute `sede` in this scope
--> $DIR/missing-derive-3.rs:20:7
|
LL | #[sede(untagged)]
| ^^^^
|
help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute
|
LL | #[serde(untagged)]
| +
error: cannot find attribute `serde` in this scope
--> $DIR/missing-derive-3.rs:14:7
|
LL | #[serde(untagged)]
| ^^^^^
|
note: `serde` is imported here, but it is a crate, not an attribute
--> $DIR/missing-derive-3.rs:4:1
|
LL | extern crate serde;
| ^^^^^^^^^^^^^^^^^^^
help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute
|
LL + #[derive(Deserialize, Serialize)]
LL | enum B {
|
```
Remove one FIXME, addressing it does not reduce the hacky-ness much, and the logic is going to be removed anyway together with the `legacy_derive_helpers` deprecation lint.
resolve: Split extern prelude into two scopes
One scope for `extern crate` items and another for `--extern` options, with the former shadowing the latter.
If in a single scope some things can overwrite other things, especially with ad hoc restrictions like `MacroExpandedExternCrateCannotShadowExternArguments`, then it's not really a single scope.
So this PR splits `Scope::ExternPrelude` into two cleaner scopes.
This is similar to how https://github.com/rust-lang/rust/pull/144131 splits module scope into two scopes for globs and non-globs, but simpler.
This eliminates the case in `failed_to_match_macro` to check for a
function-like invocation of a macro with no function-like rules.
Instead, macro kind mismatches now result in an unresolved macro, and we
detect this case in `unresolved_macro_suggestions`, which now carefully
distinguishes between a kind mismatch and other errors.
This also handles cases of forward-referenced attributes and cyclic
attributes.
Expand test coverage to include all of these cases.
Review everything that uses `MacroKind`, and switch anything that could
refer to more than one kind to use `MacroKinds`.
Add a new `SyntaxExtensionKind::MacroRules` for `macro_rules!` macros,
using the concrete `MacroRulesMacroExpander` type, and have it track
which kinds it can handle. Eliminate the separate optional `attr_ext`,
now that a `SyntaxExtension` can handle multiple macro kinds.
This also avoids the need to downcast when calling methods on
`MacroRulesMacroExpander`, such as `get_unused_rule`.
Integrate macro kind checking into name resolution's
`sub_namespace_match`, so that we only find a macro if it's the right
type, and eliminate the special-case hack for attributes.
When trying to construct a struct that has a public field of a private type, suggest using `..` if that field has a default value.
```
error[E0603]: struct `Priv1` is private
--> $DIR/non-exhaustive-ctor.rs:25:39
|
LL | let _ = S { field: (), field1: m::Priv1 {} };
| ------ ^^^^^ private struct
| |
| while setting this field
|
note: the struct `Priv1` is defined here
--> $DIR/non-exhaustive-ctor.rs:14:4
|
LL | struct Priv1 {}
| ^^^^^^^^^^^^
help: the field `field1` you're trying to set has a default value, you can use `..` to use it
|
LL | let _ = S { field: (), .. };
| ~~
```
Resolver: introduce a conditionally mutable Resolver for (non-)speculative resolution.
This pr introduces a `CmResolver`, a wrapper around the main resolver which gives out mutable access given a condition.
`CmResolver` only allows mutation when we’re not in speculative import resolution. This ensures we can’t accidentally mutate the resolver during this process, which is important as we move towards a batched resolution algorithm.
This also changes functions that are used during speculative import resolution to take a `CmResolver` instead of a `&mut Resolver`.
Also introduces a new kind of "smart pointer" which has the behaviour described above:
```rust
/// A wrapper around a mutable reference that conditionally allows mutable access.
pub(crate) struct RefOrMut<'a, T> {
p: &'a mut T,
mutable: bool,
}
type CmResolver<'r, 'ra, 'tcx> = RefOrMut<'r, Resolver<'ra, 'tcx>>;
```
r? petrochenkov
resolve: Cleanups and micro-optimizations to extern prelude
This is what can be done without changing the structure of `ExternPreludeEntry`, like in https://github.com/rust-lang/rust/pull/144737.
See individual commits for details.
Detect more `cfg`d out items in resolution errors
Use a visitor to collect *all* items (including those nested) that were stripped behind a `cfg` condition.
```
error[E0425]: cannot find function `f` in this scope
--> $DIR/nested-cfg-attrs.rs:4:13
|
LL | fn main() { f() }
| ^ not found in this scope
|
note: found an item that was configured out
--> $DIR/nested-cfg-attrs.rs:2:4
|
LL | fn f() {}
| ^
note: the item is gated here
--> $DIR/nested-cfg-attrs.rs:1:35
|
LL | #[cfg_attr(all(), cfg_attr(all(), cfg(FALSE)))]
| ^^^^^^^^^^
```
```
error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner`
--> $DIR/diagnostics-cross-crate.rs:18:23
|
LL | cfged_out::inner::doesnt_exist::hello();
| ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner`
|
note: found an item that was configured out
--> $DIR/auxiliary/cfged_out.rs:6:13
|
LL | #[cfg(false)]
| ----- the item is gated here
LL | pub mod doesnt_exist {
| ^^^^^^^^^^^^
```
Use a visitor to collect *all* items (including those nested) that were stripped behind a `cfg` condition.
```
error[E0425]: cannot find function `f` in this scope
--> $DIR/nested-cfg-attrs.rs:4:13
|
LL | fn main() { f() }
| ^ not found in this scope
|
note: found an item that was configured out
--> $DIR/nested-cfg-attrs.rs:2:4
|
LL | fn f() {}
| ^
note: the item is gated here
--> $DIR/nested-cfg-attrs.rs:1:35
|
LL | #[cfg_attr(all(), cfg_attr(all(), cfg(FALSE)))]
| ^^^^^^^^^^
```
There are many places that join path segments with `::` to produce a
string. A lot of these use `join("::")`. Many in rustdoc use
`join_with_double_colon`, and a few use `.joined("..")`. One in Clippy
uses `itertools::join`. A couple of them look for `kw::PathRoot` in the
first segment, which can be important.
This commit introduces `rustc_ast::join_path_{syms,ident}` to do the
joining for everyone. `rustc_ast` is as good a location for these as
any, being the earliest-running of the several crates with a `Path`
type. Two functions are needed because `Ident` printing is more complex
than simple `Symbol` printing.
The commit also removes `join_with_double_colon`, and
`estimate_item_path_byte_length` with it.
There are still a handful of places that join strings with "::" that are
unchanged. They are not that important: some of them are in tests, and
some of them first split a path around "::" and then rejoin with "::".
This fixes one test case where `{{root}}` shows up in an error message.
suggest declaring modules when file found but module not defined
suggests declaring modules when a module is found but not defined, i.e
```
├── main.rs: `use thing::thang;`
└── thing.rs: `struct thang`
```
or
```
├── main.rs: `use thing::thang;`
└── thing
└── mod.rs: `struct thang`
```
which currently is just
```rust
error[E0432]: unresolved import `yeah`
--> src/main.rs:1:1
|
1 | use thing::thang;
| ^^^^^ use of unresolved module or unlinked crate `thing`
|
```
but now would have this nice help:
```text
= help: you may have forgotten to declare the module `thing`. use `mod thing` in this file to declare this module.
```
```
error: cannot find attribute `empty_helper` in this scope
--> $DIR/derive-helper-legacy-limits.rs:17:3
|
LL | #[empty_helper]
| ^^^^^^^^^^^^
|
help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute
|
LL + #[derive(Empty)]
LL | struct S2;
|
```
Look at proc-macro attributes when encountering unknown attribute
```
error: cannot find attribute `sede` in this scope
--> src/main.rs:18:7
|
18 | #[sede(untagged)]
| ^^^^
|
help: the derive macros `Serialize` and `Deserialize` accept the similarly named `serde` attribute
|
18 | #[serde(untagged)]
| ~~~~~
error: cannot find attribute `serde` in this scope
--> src/main.rs:12:7
|
12 | #[serde(untagged)]
| ^^^^^
|
= note: `serde` is in scope, but it is a crate, not an attribute
help: `serde` is an attribute that can be used by the derive macros `Serialize` and `Deserialize`, you might be missing a `derive` attribute
|
10 | #[derive(Serialize, Deserialize)]
|
```
It bugs me when variables of type `Ident` are called `name`. It leads to
silly things like `name.name`. `Ident` variables should be called
`ident`, and `name` should be used for variables of type `Symbol`.
This commit improves things by by doing `s/name/ident/` on a bunch of
`Ident` variables. Not all of them, but a decent chunk.