-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Implement tool_attributes feature (RFC 2103) #47773
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Conversation
Hmm. Should I add the section to the unstable book after this PR is merged, or am I missing something? I followed the instruction in https://forge.rust-lang.org/feature-guide.html. |
@topecongiro The problem is that unstable book file should be written in hyphenated lower case. Try to rename it as |
@kennytm Thank you! |
src/libsyntax/ast.rs
Outdated
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] | ||
pub struct MetaItem { | ||
pub name: Name, | ||
pub name: MetaItemName, | ||
pub node: MetaItemKind, | ||
pub span: Span, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Contents of ast::Attribute
and ast::MetaItem
are the same thing by definition, but in the compiler they diverged significantly in recent months.
An attribute is a "macro invocation" that consists of a Path
and a TokenStream
, MetaItem
should have the same structure and they should share code, ideally.
I'd rather do this refactoring instead of adding temporary hacks like Vec<Name>
, preferably in a separate PR.
(The attribute/meta-item Path
goes through usual path resolution procedure, and that's where resolution of the "tool module" rustfmt
or clippy
should be added as well, ideally.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks fine to me, but I think someone more active in compiler work should sign off too.
src/libsyntax/ast.rs
Outdated
/// Unscoped name, e.g. `name` in `#[name(..)]`. | ||
Single(Name), | ||
/// Scoped name, e.g. `rustfmt::skip` in `#[rustfmt::skip]`. | ||
Scoped(Vec<Name>), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we use a Path
here, rather than Vec<Name>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact I wonder if we could use Path
instead of MetaItemName
and always treat attributes as paths rather than names (we have to do this for macro attributes anyway)
@petrochenkov @nrc Thank you for you reviews! So I am going to replace EDIT: I actually kept the tool name checking in feature_gate.rs. |
54f59e1
to
b6a9355
Compare
@@ -708,6 +708,22 @@ pub trait PrintState<'a> { | |||
Ok(()) | |||
} | |||
|
|||
fn print_attribute_path(&mut self, path: &ast::Path) -> io::Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like existing print_path
can be used instead of introducing this new function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
print_path
is not a method of PrintState
trait, so I am not sure how to exploit it. Should I write like self.writer().word(&path_to_string(path))
?
|
let (span, name) = match tokens.next() { | ||
Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name), | ||
let name = match tokens.next() { | ||
Some(TokenTree::Token(span, Token::Ident(ident))) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like an imitation of parse_path
, but I don't know how make the normal version and tokenstream version reuse the same code.
Could you leave a FIXME comment here?
src/libsyntax/parse/parser.rs
Outdated
@@ -1972,26 +1972,6 @@ impl<'a> Parser<'a> { | |||
Ok(ast::Path { segments, span: lo.to(self.prev_span) }) | |||
} | |||
|
|||
/// Like `parse_path`, but also supports parsing `Word` meta items into paths for back-compat. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where does this special back-compat support of Word
meta items happen now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, wait parse_path_allowing_meta
is reintroduced in the next commit.
src/libsyntax/attr.rs
Outdated
@@ -205,6 +211,10 @@ impl NestedMetaItem { | |||
} | |||
} | |||
|
|||
fn name_from_path(path: &ast::Path) -> Name { | |||
path.segments.iter().next().unwrap().identifier.name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you use the last segment instead?
In #[a::b::c]
a
and b
are modules (possibly "tool modules") in which the attribute c
is defined, and the last segment c
is the attribute itself.
added to it in the future", | ||
attr.path)); | ||
if attr.is_scoped() { | ||
gate_feature!(self, tool_attributes, attr.span, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This solution is 100% technical debt, but I guess it can work while everything is unstable, and we go into this branch only if previous ways to resolve the attribute failed.
I described the proper solution in rust-lang/rfcs#2103 (comment).
TLDR: a::b::c
in #[a::b::c(...)]
should be resolved as a usual path in macro namespace and therefore rustfmt
and clippy
should be added into the language prelude as special modules (primitive types u8
, u16
, etc work in very similar way).
I don't suggest to implement this now though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't suggest to implement this now though.
But I suggest to implement this eventually, if you plan to continue working on macros/attributes and name resolution in rustc.
src/libsyntax/feature_gate.rs
Outdated
self.parse_sess.span_diagnostic, | ||
attr.span, | ||
E0693, | ||
"An unkown tool name found in scoped attributes: `{}`.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo "unkown" -> "unknown"
@petrochenkov Thank you for your reviews and I am sorry for the late reply. I hope that I can update this PR today... |
@bors r+ |
📌 Commit 30214c9 has been approved by |
⌛ Testing commit 30214c90d560ddc3b6e83992f34afb340dd43d5e with merge cac046403a27dd42eb53ef8b9c94801592a12b5d... |
💔 Test failed - status-travis |
And fix some typos
Rebased against master. I have a problem reproducing the above failures locally... running |
@topecongiro It is possible that this is an expected pretty-printer failure, then you can disable the test with |
@petrochenkov Thank you for your advice, I could reproduce this locally. I cannot tell whether this is an expected pretty-printer failure or not. I looked at the original PR that added this test (#40346). It looks like now arbitrary tokens could appear as arguments to procedural macros. So I guess that this PR is trying to parse random tokens inside procedural macros as some valid paths when it shouldn't? Again, I am not sure, though. |
self.parse_sess.span_diagnostic, | ||
attr.span, | ||
E0693, | ||
"An unknown tool name found in scoped attributes: `{}`.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: error messages conventionally start with a lower-case letter.
(Same in the feature gate message below.)
@topecongiro I don't quite see where is the difference in name resolution comes from. Please make sure the logic for single-segment attribute paths is identical to what it was before. For example, |
@topecongiro can you fix that failing test so the PR can be merged? |
☔ The latest upstream changes (presumably #48520) made this pull request unmergeable. Please resolve the merge conflicts. |
Thank you for your hard work, @topecongiro ! However, we haven't heard from you in a few weeks, so I'm going to close this PR for now to keep the queue tidy. Please feel free to reopen this when you have a chance to fix the merge conflicts and the failing test. |
This PR implements a
tool_attributes
feature. If this implementaion is acceptable, I am going to create a similar PR that implementstool_lints
.This PR only adds
rustfmt
andclippy
to known tool name list. The list resides in libsyntax/attr.rs.cc #44690.
r? @nrc