Skip to content
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

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/doc/unstable-book/src/language-features/tool-attributes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# `tool_attributes`

The tracking issue for this feature is: [#44690]

[#44690]: https://github.com/rust-lang/rust/issues/44690

------------------------

Tool attributes let you use scoped attributes to control the behavior
of certain tools.

Currently tool names which can be appear in scoped attributes are restricted to
`clippy` and `rustfmt`.

## An example

```rust
#![feature(tool_attributes)]

#[rustfmt::skip]
fn foo() { println!("hello, world"); }

fn main() {
foo();
}
```
11 changes: 3 additions & 8 deletions src/librustc/hir/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,8 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
self.tcx.target_features_enabled(self.tcx.hir.local_def_id(item.id));

for attr in &item.attrs {
if let Some(name) = attr.name() {
if name == "inline" {
self.check_inline(attr, item, target)
}
if attr.name() == "inline" {
self.check_inline(attr, item, target)
}
}

Expand Down Expand Up @@ -81,10 +79,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
// ```
let hints: Vec<_> = item.attrs
.iter()
.filter(|attr| match attr.name() {
Some(name) => name == "repr",
None => false,
})
.filter(|attr| attr.name() == "repr")
.filter_map(|attr| attr.meta_item_list())
.flat_map(|hints| hints)
.collect();
Expand Down
21 changes: 14 additions & 7 deletions src/librustc/ich/impls_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for [ast::Attribute] {
let filtered: AccumulateVec<[&ast::Attribute; 8]> = self
.iter()
.filter(|attr| {
!attr.is_sugared_doc &&
attr.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true)
!attr.is_sugared_doc && !hcx.is_ignored_attr(attr.name())
})
.collect();

Expand All @@ -190,12 +189,23 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for [ast::Attribute] {
}
}

impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::Path {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
hasher: &mut StableHasher<W>) {
self.segments.len().hash_stable(hcx, hasher);
for segment in &self.segments {
segment.identifier.name.hash_stable(hcx, hasher);
}
}
}

impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::Attribute {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
hasher: &mut StableHasher<W>) {
// Make sure that these have been filtered out.
debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true));
debug_assert!(!hcx.is_ignored_attr(self.name()));
debug_assert!(!self.is_sugared_doc);

let ast::Attribute {
Expand All @@ -208,10 +218,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ast::Attribute {
} = *self;

style.hash_stable(hcx, hasher);
path.segments.len().hash_stable(hcx, hasher);
for segment in &path.segments {
segment.identifier.name.hash_stable(hcx, hasher);
}
path.hash_stable(hcx, hasher);
for tt in tokens.trees() {
tt.hash_stable(hcx, hasher);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/lint/levels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ impl<'a> LintLevelsBuilder<'a> {
"malformed lint attribute");
};
for attr in attrs {
let level = match attr.name().and_then(|name| Level::from_str(&name.as_str())) {
let level = match Level::from_str(&attr.name().as_str()) {
None => continue,
Some(lvl) => lvl,
};
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
} else {
// Emit errors for non-staged-api crates.
for attr in attrs {
let tag = unwrap_or!(attr.name(), continue);
let tag = attr.name();
if tag == "unstable" || tag == "stable" || tag == "rustc_deprecated" {
attr::mark_used(attr);
self.tcx.sess.span_err(attr.span(), "stability attributes may not be used \
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_driver/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1012,7 +1012,7 @@ impl RustcDefaultCalls {
let mut cfgs = Vec::new();
for &(name, ref value) in sess.parse_sess.config.iter() {
let gated_cfg = GatedCfg::gate(&ast::MetaItem {
name,
name: ast::Path::from_ident(DUMMY_SP, name.to_ident()),
node: ast::MetaItemKind::Word,
span: DUMMY_SP,
});
Expand Down
3 changes: 1 addition & 2 deletions src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -663,9 +663,8 @@ impl LintPass for DeprecatedAttr {

impl EarlyLintPass for DeprecatedAttr {
fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) {
let name = unwrap_or!(attr.name(), return);
for &&(n, _, ref g) in &self.depr_attrs {
if name == n {
if attr.name() == n {
if let &AttributeGate::Gated(Stability::Deprecated(link),
ref name,
ref reason,
Expand Down
1 change: 0 additions & 1 deletion src/librustc_lint/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
#![feature(rustc_diagnostic_macros)]
#![feature(slice_patterns)]

#[macro_use]
extern crate syntax;
#[macro_use]
extern crate rustc;
Expand Down
3 changes: 1 addition & 2 deletions src/librustc_lint/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,6 @@ impl LintPass for UnusedAttributes {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
debug!("checking attribute: {:?}", attr);
let name = unwrap_or!(attr.name(), return);

// Note that check_name() marks the attribute as used if it matches.
for &(ref name, ty, _) in BUILTIN_ATTRIBUTES {
match ty {
Expand All @@ -195,6 +193,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
}
}

let name = attr.name();
if !attr::is_used(attr) {
debug!("Emitting warning for: {:?}", attr);
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_resolve/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ impl<'a> base::Resolver for Resolver<'a> {
fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>)
-> Option<ast::Attribute> {
for i in 0..attrs.len() {
let name = unwrap_or!(attrs[i].name(), continue);
let name = attrs[i].name();

if self.session.plugin_attributes.borrow().iter()
.any(|&(ref attr_nm, _)| name == &**attr_nm) {
Expand All @@ -230,7 +230,7 @@ impl<'a> base::Resolver for Resolver<'a> {

// Check for legacy derives
for i in 0..attrs.len() {
let name = unwrap_or!(attrs[i].name(), continue);
let name = attrs[i].name();

if name == "derive" {
let result = attrs[i].parse_list(&self.session.parse_sess, |parser| {
Expand Down
Loading