Fix nonsensical #[path] attributes being silently allowed#157903
Fix nonsensical #[path] attributes being silently allowed#157903krishkumarwork3-beep wants to merge 1 commit into
#[path] attributes being silently allowed#157903Conversation
|
Some changes occurred in compiler/rustc_passes/src/check_attr.rs cc @jdonszelmann, @JonathanBrouwer Some changes occurred in compiler/rustc_hir/src/attrs cc @jdonszelmann, @JonathanBrouwer Some changes occurred in compiler/rustc_attr_parsing |
|
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @theemathas (or someone else) some time within the next two weeks. Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (
|
This comment has been minimized.
This comment has been minimized.
7b3ca8d to
2ccb399
Compare
|
Hi @krishkumarwork3-beep, thanks for your PR. I’m afraid @theemathas probably won’t be able to review it, as we need someone from the compiler team for this, so I’ll re-assign another member. @rustbot reroll |
This comment has been minimized.
This comment has been minimized.
2ccb399 to
b206d94
Compare
This comment has been minimized.
This comment has been minimized.
|
@rustbot review The PR - tidy check appears to be failing due to a tidy tool crash |
|
The CI is failing due to the absence of a newline in your test file. |
|
(You can reproduce this locally with |
b206d94 to
db64cfb
Compare
|
thanks @JonathanBrouwer and @Kivooeo |
|
This is also a breaking change. Do we want to/need to crater? |
| if let ItemKind::Mod(_, nested_mod) = &item.kind { | ||
| let nested_inner = nested_mod.spans.inner_span; | ||
| let nested_item_span = self.tcx.hir_span(item.hir_id()); | ||
| return self |
There was a problem hiding this comment.
Shouldn't we be able to just look whether a path attr is present on the nested module? That way we don't have to go through the source map
There was a problem hiding this comment.
Good point! However, checking for a #[path] attribute on the nested module doesn't tell us if the module is external , a module can be external (mod foo;) without having a #[path] attribute, and an inline module (mod foo {}) can have one. The actual distinction between inline and external is whether the module body is in the same file, which is what the source map check captures. I've factored the source map comparison into a shared is_inline closure to avoid the duplication you pointed out. Happy to revisit if you have a different approach in mind!
| let is_outer_attr = matches!(style, ast::AttrStyle::Outer); | ||
| let is_inner_attr = matches!(style, ast::AttrStyle::Inner); | ||
|
|
||
| let inner_span = module.spans.inner_span; |
There was a problem hiding this comment.
Same here. In fact, even if looking at path attrs doesn't work, this check in the source map seems very similar to the one below. Might want to factor it out into a functionm
There was a problem hiding this comment.
Done, I have factored the source map file name comparison into a local is_inline closure reused for both the parent and nested module checks in latest commit
| if mod_span.from_expansion() { | ||
| return; | ||
| } | ||
| let node = self.tcx.hir_node(hir_id); |
There was a problem hiding this comment.
I believe we have a .hir_item() method that returns an option?
There was a problem hiding this comment.
I looked into this - tcx.hir_item() takes an ItemId rather than a HirId, so it can't be used directly here. I've replaced the hir_node + match pattern with let hir::Node::Item(item) = self.tcx.hir_node(hir_id) else { return; } which achieves the same clean early-return pattern. Let me know if you had a different method in mind!
Thanks @jdonszelmann for your suggestions
|
Reminder, once the PR becomes ready for a review, use |
This comment has been minimized.
This comment has been minimized.
If this is the change we want, the answer is yes |
|
And it needs to be a FCP by lang if it's a breaking change (depending on fallout, whether a FCW lint w/ migration period is needed). |
There was a problem hiding this comment.
Suggestion: please edit your PR description to more meaningfully reflect what is being changed about the language (reviewers do not need a list of files being changed; they can see that through the diff already). Please describe e.g.:
- Is this a breaking change?
- Can you give an example of what previously worked, but now won't after this PR?
- What are the positions where nonsensical
#[path]attributes were being silently allowed, but are now loudly rejected?
For an example, seee #145463 (comment)
There was a problem hiding this comment.
yes @jieyouxu i have updated the PR description as suggested by you
thanks for the suggestion ,I will take care of it in future
In that case I think it can be lang nominated right? |
Yes, but please only nominate for lang after there's a more concrete proposal (incl. breakage estimation via crater analysis) and something that's more explicit (e.g. see linked PR summary) so lang doesn't have to dig through context. |
| // ERROR: #![path] inside module where submodule is inline (has body) | ||
| mod thread_inline_sub { //~ ERROR attribute `#[path]` is useless here as there are no nested external modules | ||
| #![path = "thread_files"] | ||
| #[path = "tls.rs"] | ||
| mod local_data {} //~ ERROR attribute `#[path]` is useless on inline modules | ||
| } |
There was a problem hiding this comment.
You claim at #157260 (comment) that this code will not produce a warning. This test shows that the code produces a hard error instead. Could you explain?
There was a problem hiding this comment.
mod thread_inline_sub { //~ ERROR attribute #[path] is useless here as there are no nested external modules
#![path = "thread_files"]
#[path = "tls.rs"]
mod local_data {} //~ ERROR attribute #[path] is useless on inline modules
} is different from
mod thread_inline_sub {
#![path = "thread_files"]
#[path = "tls.rs"]
mod local_data;
} what @JonathanBrouwer asked for
in the case 1
mod local_data {} has a body {} → it's inline → compiler already knows its content, #[path] is meaningless ,since local_data is inline (not external), thread_inline_sub has no external submodules → #![path] is also meaningless so a hard error is produced
and
in case 2
mod local_data; has a semicolon → it's external → compiler needs #[path = "tls.rs"] to find the file,since local_data is external, thread_inline_sub has an external submodule → #![path = "thread_files"] is meaningful as a directory hint so no error should come
Changes: - compiler/rustc_hir/src/attrs/data_structures.rs: Extended AttributeKind::Path variant to carry AttrStyle alongside the Symbol, enabling inner/outer attribute distinction - compiler/rustc_attr_parsing/src/attributes/path.rs: Updated convert in SingleAttributeParser for PathParser to pass cx.attr_style into AttributeKind::Path - compiler/rustc_passes/src/check_attr.rs: Added check_path_attribute to validate and emit errors for useless #[path] and #![path] attributes on inline modules - compiler/rustc_passes/src/errors.rs: Added UselessPathAttribute and UselessInnerPathAttribute error structs - ests/ui/attributes/path-inline-module.rs: UI tests covering all four validation cases - ests/ui/attributes/path-inline-module.stderr: Expected diagnostics for the above tests
db64cfb to
667bdba
Compare
|
Requested reviewer is already assigned to this pull request. Please choose another assignee. |
|
I did say this should at most be a warning. The following is reasonable to me: #[path = "thread_files"]
mod thread {
#[cfg(feature = "enable_tls")]`
#[path = "tls.rs"]
mod local_data; // external (semicolon), path is meaningful
}it would be weird if that suddenly emits a hard error when |
|
View all comments
r? @jdonszelmann
Fixes #157260
Previously, the compiler silently accepted nonsensical uses of the
#[path]attribute. This PR makes these into hard errors.
What are the positions where nonsensical
#[path]attributes were beingsilently allowed, but are now loudly rejected?
Position 1:
#[path]on an inline module with no external submodulesPosition 2:
#[path]on an inline module whose submodules are also inlinePosition 3:
#![path]inside a module with no external submodulesPosition 4:
#![path]inside a module where the submodule is inline (has body{})What remains valid (no error):
Is this a breaking change?
Yes — code that previously compiled without errors will now emit hard errors.