-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement tool_attributes feature (RFC 2103) #47773
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