From df188b8f976a49c226068e42a6c3ae2e15956daf Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 11 May 2017 10:26:07 +0200 Subject: [PATCH 1/8] Add lint for unused macros --- src/librustc/lint/builtin.rs | 7 +++++++ src/librustc_driver/driver.rs | 2 ++ src/librustc_lint/lib.rs | 3 ++- src/librustc_resolve/lib.rs | 7 +++++++ src/librustc_resolve/macros.rs | 29 +++++++++++++++++++++++++++-- src/libsyntax/ext/base.rs | 6 ++++++ 6 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index e681d55cf94b8..07140f71aebaa 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -76,6 +76,12 @@ declare_lint! { "detects unreachable patterns" } +declare_lint! { + pub UNUSED_MACROS, + Warn, + "detects macros that were not used" +} + declare_lint! { pub WARNINGS, Warn, @@ -259,6 +265,7 @@ impl LintPass for HardwiredLints { DEAD_CODE, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, + UNUSED_MACROS, WARNINGS, UNUSED_FEATURES, STABLE_FEATURES, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 8fddbe110b0e6..eff5d2b2f37f1 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -699,6 +699,8 @@ pub fn phase_2_configure_and_expand(sess: &Session, let krate = ecx.monotonic_expander().expand_crate(krate); + ecx.check_unused_macros(); + let mut missing_fragment_specifiers: Vec<_> = ecx.parse_sess.missing_fragment_specifiers.borrow().iter().cloned().collect(); missing_fragment_specifiers.sort(); diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 2d0b5a6a51c6b..479c7206cb4cb 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -171,7 +171,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UNUSED_MUST_USE, UNUSED_UNSAFE, PATH_STATEMENTS, - UNUSED_ATTRIBUTES); + UNUSED_ATTRIBUTES, + UNUSED_MACROS); // Guidelines for creating a future incompatibility lint: // diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c4512cb38c4e2..f78dd4890e2ce 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1195,6 +1195,12 @@ pub struct Resolver<'a> { pub whitelisted_legacy_custom_derives: Vec, pub found_unresolved_macro: bool, + // List of macros that we need to warn about as being unused. + // The bool is true if the macro is unused, and false if its used. + // Setting a bool to false should be much faster than removing a single + // element from a FxHashSet. + unused_macros: FxHashMap, + // Maps the `Mark` of an expansion to its containing module or block. invocations: FxHashMap>, @@ -1400,6 +1406,7 @@ impl<'a> Resolver<'a> { potentially_unused_imports: Vec::new(), struct_constructors: DefIdMap(), found_unresolved_macro: false, + unused_macros: FxHashMap(), } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index c08421cb9374e..29ca163b0b4b7 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -16,7 +16,7 @@ use resolve_imports::ImportResolver; use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex}; use rustc::hir::def::{Def, Export}; use rustc::hir::map::{self, DefCollector}; -use rustc::ty; +use rustc::{ty, lint}; use syntax::ast::{self, Name, Ident}; use syntax::attr::{self, HasAttrs}; use syntax::errors::DiagnosticBuilder; @@ -291,12 +291,35 @@ impl<'a> base::Resolver for Resolver<'a> { }, }; self.macro_defs.insert(invoc.expansion_data.mark, def.def_id()); + self.unused_macros.get_mut(&def.def_id()).map(|m| *m = false); Ok(Some(self.get_macro(def))) } fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) -> Result, Determinacy> { - self.resolve_macro_to_def(scope, path, kind, force).map(|def| self.get_macro(def)) + self.resolve_macro_to_def(scope, path, kind, force).map(|def| { + self.unused_macros.get_mut(&def.def_id()).map(|m| *m = false); + self.get_macro(def) + }) + } + + fn check_unused_macros(&self) { + for (did, _) in self.unused_macros.iter().filter(|&(_, b)| *b) { + let span = match *self.macro_map[did] { + SyntaxExtension::NormalTT(_, sp, _) => sp, + SyntaxExtension::IdentTT(_, sp, _) => sp, + _ => None + }; + if let Some(span) = span { + let lint = lint::builtin::UNUSED_MACROS; + let msg = "unused macro".to_string(); + // We are using CRATE_NODE_ID here even though its inaccurate, as we + // sadly don't have the NodeId of the macro definition. + self.session.add_lint(lint, ast::CRATE_NODE_ID, span, msg); + } else { + bug!("attempted to create unused macro error, but span not available"); + } + } } } @@ -687,6 +710,8 @@ impl<'a> Resolver<'a> { if attr::contains_name(&item.attrs, "macro_export") { let def = Def::Macro(def_id, MacroKind::Bang); self.macro_exports.push(Export { name: ident.name, def: def, span: item.span }); + } else { + self.unused_macros.insert(def_id, true); } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index f731c5abdd6a1..b0253ec3905c9 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -589,6 +589,7 @@ pub trait Resolver { -> Result>, Determinacy>; fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) -> Result, Determinacy>; + fn check_unused_macros(&self); } #[derive(Copy, Clone, Debug)] @@ -618,6 +619,7 @@ impl Resolver for DummyResolver { _force: bool) -> Result, Determinacy> { Err(Determinacy::Determined) } + fn check_unused_macros(&self) {} } #[derive(Clone)] @@ -800,6 +802,10 @@ impl<'a> ExtCtxt<'a> { pub fn name_of(&self, st: &str) -> ast::Name { Symbol::intern(st) } + + pub fn check_unused_macros(&self) { + self.resolver.check_unused_macros(); + } } /// Extract a string literal from the macro expanded version of `expr`, From db82c57cb7ff7f4f629ceeaefdbc693d2886fda7 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 12 May 2017 08:05:52 +0200 Subject: [PATCH 2/8] Extend the libsyntax visitor to work over macro defs --- src/libsyntax/visit.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 2e42c6986e64e..1855681221b8d 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -27,6 +27,7 @@ use abi::Abi; use ast::*; use syntax_pos::Span; use codemap::Spanned; +use tokenstream::ThinTokenStream; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { @@ -110,6 +111,9 @@ pub trait Visitor<'ast>: Sized { // definition in your trait impl: // visit::walk_mac(self, _mac) } + fn visit_mac_def(&mut self, _mac: &'ast ThinTokenStream, _id: NodeId) { + // Nothing to do + } fn visit_path(&mut self, path: &'ast Path, _id: NodeId) { walk_path(self, path) } @@ -288,7 +292,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { walk_list!(visitor, visit_trait_item, methods); } ItemKind::Mac(ref mac) => visitor.visit_mac(mac), - ItemKind::MacroDef(..) => {}, + ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id), } walk_list!(visitor, visit_attribute, &item.attrs); } From d14d194f61bfd775411c2450e1d939bbb06542b9 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 12 May 2017 08:10:52 +0200 Subject: [PATCH 3/8] Support #[allow] etc logic on a per macro level This commit extends the current unused macro linter to support directives like #[allow(unused_macros)] or #[deny(unused_macros)] directly next to the macro definition, or in one of the modules the macro is inside. Before, we only supported such directives at a per crate level, due to the crate's NodeId being passed to session.add_lint. We also had to implement handling of the macro's NodeId in the lint visitor. --- src/librustc/lint/context.rs | 8 ++++++++ src/librustc_plugin/registry.rs | 3 ++- src/librustc_resolve/macros.rs | 13 +++++-------- src/libsyntax/ext/base.rs | 2 +- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/ext/tt/macro_rules.rs | 6 +++++- 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 6f3e84247f797..172b74d539334 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -49,6 +49,7 @@ use hir; use hir::def_id::LOCAL_CRATE; use hir::intravisit as hir_visit; use syntax::visit as ast_visit; +use syntax::tokenstream::ThinTokenStream; /// Information about the registered lints. /// @@ -1125,6 +1126,13 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { fn visit_attribute(&mut self, attr: &'a ast::Attribute) { run_lints!(self, check_attribute, early_passes, attr); } + + fn visit_mac_def(&mut self, _mac: &'a ThinTokenStream, id: ast::NodeId) { + let lints = self.sess.lints.borrow_mut().take(id); + for early_lint in lints { + self.early_lint(&early_lint); + } + } } enum CheckLintNameResult { diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index cdde56f5f634b..3027489d65be2 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -103,7 +103,8 @@ impl<'a> Registry<'a> { } self.syntax_exts.push((name, match extension { NormalTT(ext, _, allow_internal_unstable) => { - NormalTT(ext, Some(self.krate_span), allow_internal_unstable) + let nid = ast::CRATE_NODE_ID; + NormalTT(ext, Some((nid, self.krate_span)), allow_internal_unstable) } IdentTT(ext, _, allow_internal_unstable) => { IdentTT(ext, Some(self.krate_span), allow_internal_unstable) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 29ca163b0b4b7..f6155c6cafdea 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -305,17 +305,14 @@ impl<'a> base::Resolver for Resolver<'a> { fn check_unused_macros(&self) { for (did, _) in self.unused_macros.iter().filter(|&(_, b)| *b) { - let span = match *self.macro_map[did] { - SyntaxExtension::NormalTT(_, sp, _) => sp, - SyntaxExtension::IdentTT(_, sp, _) => sp, + let id_span = match *self.macro_map[did] { + SyntaxExtension::NormalTT(_, isp, _) => isp, _ => None }; - if let Some(span) = span { + if let Some((id, span)) = id_span { let lint = lint::builtin::UNUSED_MACROS; - let msg = "unused macro".to_string(); - // We are using CRATE_NODE_ID here even though its inaccurate, as we - // sadly don't have the NodeId of the macro definition. - self.session.add_lint(lint, ast::CRATE_NODE_ID, span, msg); + let msg = "unused macro definition".to_string(); + self.session.add_lint(lint, id, span, msg); } else { bug!("attempted to create unused macro error, but span not available"); } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index b0253ec3905c9..86202f77dbf8a 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -535,7 +535,7 @@ pub enum SyntaxExtension { /// /// The `bool` dictates whether the contents of the macro can /// directly use `#[unstable]` things (true == yes). - NormalTT(Box, Option, bool), + NormalTT(Box, Option<(ast::NodeId, Span)>, bool), /// A function-like syntax extension that has an extra ident before /// the block. diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index a8aa103f80a8e..75dd09f23115e 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -469,7 +469,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { call_site: span, callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), - span: exp_span, + span: exp_span.map(|(_, s)| s), allow_internal_unstable: allow_internal_unstable, }, }); diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index f959ccc989e2e..0c787dcbecb9a 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -252,7 +252,11 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) valid: valid, }); - NormalTT(exp, Some(def.span), attr::contains_name(&def.attrs, "allow_internal_unstable")) + NormalTT( + exp, + Some((def.id, def.span)), + attr::contains_name(&def.attrs, "allow_internal_unstable") + ) } fn check_lhs_nt_follows(sess: &ParseSess, From ba0601d4b6b3a84cb7e8c2781b71491c17abb910 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 12 May 2017 08:21:13 +0200 Subject: [PATCH 4/8] libcore: #[allow] some unused macros --- src/libcore/num/wrapping.rs | 1 + src/libcore/ops.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 013f02685bad1..6cc374b13b7b3 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -12,6 +12,7 @@ use super::Wrapping; use ops::*; +#[allow(unused_macros)] macro_rules! sh_impl_signed { ($t:ident, $f:ident) => ( #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 391b606f613f2..ca6438c0fa715 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -763,6 +763,7 @@ macro_rules! neg_impl_numeric { ($($t:ty)*) => { neg_impl_core!{ x => -x, $($t)*} } } +#[allow(unused_macros)] macro_rules! neg_impl_unsigned { ($($t:ty)*) => { neg_impl_core!{ x => { From b36d23c8afeab39df09fa447b37ccb8797861382 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 12 May 2017 09:53:58 +0200 Subject: [PATCH 5/8] Add test, and fix the other tests --- .../proc-macro/resolve-error.rs | 1 + ...te-allow-internal-unstable-nested-macro.rs | 2 + .../feature-gate-allow-internal-unstable.rs | 2 + .../compile-fail/invalid-macro-matcher.rs | 2 + src/test/compile-fail/issue-21356.rs | 2 + src/test/compile-fail/issue-39388.rs | 2 + src/test/compile-fail/issue-39404.rs | 1 + src/test/compile-fail/issue-5067.rs | 2 + .../compile-fail/macro-expansion-tests.rs | 2 + src/test/compile-fail/macro-follow.rs | 2 + .../compile-fail/macro-followed-by-seq-bad.rs | 2 + .../macro-input-future-proofing.rs | 2 + src/test/compile-fail/macro-shadowing.rs | 2 + .../unused-macro-with-bad-frag-spec.rs | 2 + .../unused-macro-with-follow-violation.rs | 2 + src/test/compile-fail/unused-macro.rs | 39 +++++++++++++++++++ .../compile-fail/user-defined-macro-rules.rs | 2 + 17 files changed, 69 insertions(+) create mode 100644 src/test/compile-fail/unused-macro.rs diff --git a/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs b/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs index e0066dd43be89..ddd8631f02e62 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs @@ -14,6 +14,7 @@ // aux-build:bang_proc_macro.rs #![feature(proc_macro)] +#![allow(unused_macros)] #[macro_use] extern crate derive_foo; diff --git a/src/test/compile-fail/feature-gate-allow-internal-unstable-nested-macro.rs b/src/test/compile-fail/feature-gate-allow-internal-unstable-nested-macro.rs index 1aabe6b87dff5..9af501b141955 100644 --- a/src/test/compile-fail/feature-gate-allow-internal-unstable-nested-macro.rs +++ b/src/test/compile-fail/feature-gate-allow-internal-unstable-nested-macro.rs @@ -10,6 +10,8 @@ // gate-test-allow_internal_unstable +#![allow(unused_macros)] + macro_rules! bar { () => { // more layers don't help: diff --git a/src/test/compile-fail/feature-gate-allow-internal-unstable.rs b/src/test/compile-fail/feature-gate-allow-internal-unstable.rs index 8a2d8dddac074..61a362cb37fb2 100644 --- a/src/test/compile-fail/feature-gate-allow-internal-unstable.rs +++ b/src/test/compile-fail/feature-gate-allow-internal-unstable.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + #[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps macro_rules! foo { () => {} diff --git a/src/test/compile-fail/invalid-macro-matcher.rs b/src/test/compile-fail/invalid-macro-matcher.rs index a0ac5d4c72041..d710f5647dd9f 100644 --- a/src/test/compile-fail/invalid-macro-matcher.rs +++ b/src/test/compile-fail/invalid-macro-matcher.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + macro_rules! invalid { _ => (); //~ ERROR invalid macro matcher } diff --git a/src/test/compile-fail/issue-21356.rs b/src/test/compile-fail/issue-21356.rs index fefd432e22982..f66c09291cc9e 100644 --- a/src/test/compile-fail/issue-21356.rs +++ b/src/test/compile-fail/issue-21356.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + macro_rules! test { ($wrong:t_ty ..) => () } //~^ ERROR: invalid fragment specifier `t_ty` diff --git a/src/test/compile-fail/issue-39388.rs b/src/test/compile-fail/issue-39388.rs index 6994d2199d276..15eef429eab97 100644 --- a/src/test/compile-fail/issue-39388.rs +++ b/src/test/compile-fail/issue-39388.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + macro_rules! assign { (($($a:tt)*) = ($($b:tt))*) => { //~ ERROR expected `*` or `+` $($a)* = $($b)* diff --git a/src/test/compile-fail/issue-39404.rs b/src/test/compile-fail/issue-39404.rs index 0168ae7d91017..8b49772494a66 100644 --- a/src/test/compile-fail/issue-39404.rs +++ b/src/test/compile-fail/issue-39404.rs @@ -9,6 +9,7 @@ // except according to those terms. #![deny(missing_fragment_specifier)] //~ NOTE lint level defined here +#![allow(unused_macros)] macro_rules! m { ($i) => {} } //~^ ERROR missing fragment specifier diff --git a/src/test/compile-fail/issue-5067.rs b/src/test/compile-fail/issue-5067.rs index 1c543a5fdacbb..267362f902d72 100644 --- a/src/test/compile-fail/issue-5067.rs +++ b/src/test/compile-fail/issue-5067.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + macro_rules! foo { ( $()* ) => {}; //~^ ERROR repetition matches empty token tree diff --git a/src/test/compile-fail/macro-expansion-tests.rs b/src/test/compile-fail/macro-expansion-tests.rs index ada06b0b3f452..06f2d86e5d9ba 100644 --- a/src/test/compile-fail/macro-expansion-tests.rs +++ b/src/test/compile-fail/macro-expansion-tests.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + mod macros_cant_escape_fns { fn f() { macro_rules! m { () => { 3 + 4 } } diff --git a/src/test/compile-fail/macro-follow.rs b/src/test/compile-fail/macro-follow.rs index 001bc42274b4d..6e80e9b574bcf 100644 --- a/src/test/compile-fail/macro-follow.rs +++ b/src/test/compile-fail/macro-follow.rs @@ -10,6 +10,8 @@ // // Check the macro follow sets (see corresponding rpass test). +#![allow(unused_macros)] + // FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)} macro_rules! follow_pat { ($p:pat ()) => {}; //~ERROR `$p:pat` is followed by `(` diff --git a/src/test/compile-fail/macro-followed-by-seq-bad.rs b/src/test/compile-fail/macro-followed-by-seq-bad.rs index 0ee2221bbc14b..21cc946ded605 100644 --- a/src/test/compile-fail/macro-followed-by-seq-bad.rs +++ b/src/test/compile-fail/macro-followed-by-seq-bad.rs @@ -11,6 +11,8 @@ // Regression test for issue #25436: check that things which can be // followed by any token also permit X* to come afterwards. +#![allow(unused_macros)] + macro_rules! foo { ( $a:expr $($b:tt)* ) => { }; //~ ERROR not allowed for `expr` fragments ( $a:ty $($b:tt)* ) => { }; //~ ERROR not allowed for `ty` fragments diff --git a/src/test/compile-fail/macro-input-future-proofing.rs b/src/test/compile-fail/macro-input-future-proofing.rs index fe758a4a6310f..e5fdba63b0f15 100644 --- a/src/test/compile-fail/macro-input-future-proofing.rs +++ b/src/test/compile-fail/macro-input-future-proofing.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + macro_rules! errors_everywhere { ($ty:ty <) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not allowed for `ty` ($ty:ty < foo ,) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not allowed for `ty` diff --git a/src/test/compile-fail/macro-shadowing.rs b/src/test/compile-fail/macro-shadowing.rs index 8381dc34a6a15..f5e7305e4ea9e 100644 --- a/src/test/compile-fail/macro-shadowing.rs +++ b/src/test/compile-fail/macro-shadowing.rs @@ -10,6 +10,8 @@ // aux-build:two_macros.rs +#![allow(unused_macros)] + macro_rules! foo { () => {} } macro_rules! macro_one { () => {} } #[macro_use(macro_two)] extern crate two_macros; diff --git a/src/test/compile-fail/unused-macro-with-bad-frag-spec.rs b/src/test/compile-fail/unused-macro-with-bad-frag-spec.rs index b868b79365d9f..28a69e6f9e29b 100644 --- a/src/test/compile-fail/unused-macro-with-bad-frag-spec.rs +++ b/src/test/compile-fail/unused-macro-with-bad-frag-spec.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + // Issue #21370 macro_rules! test { diff --git a/src/test/compile-fail/unused-macro-with-follow-violation.rs b/src/test/compile-fail/unused-macro-with-follow-violation.rs index e9d09bb6ad9cd..dda0d3fc9557d 100644 --- a/src/test/compile-fail/unused-macro-with-follow-violation.rs +++ b/src/test/compile-fail/unused-macro-with-follow-violation.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + macro_rules! test { ($e:expr +) => () //~ ERROR not allowed for `expr` fragments } diff --git a/src/test/compile-fail/unused-macro.rs b/src/test/compile-fail/unused-macro.rs new file mode 100644 index 0000000000000..5e401c09bda59 --- /dev/null +++ b/src/test/compile-fail/unused-macro.rs @@ -0,0 +1,39 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(unused_macros)] + +// Most simple case +macro_rules! unused { //~ ERROR: unused macro definition + () => {}; +} + +// Test macros created by macros +macro_rules! create_macro { + () => { + macro_rules! m { //~ ERROR: unused macro definition + () => {}; + } + }; +} +create_macro!(); + +#[allow(unused_macros)] +mod bar { + // Test that putting the #[deny] close to the macro's definition + // works. + + #[deny(unused_macros)] + macro_rules! unused { //~ ERROR: unused macro definition + () => {}; + } +} + +fn main() {} diff --git a/src/test/compile-fail/user-defined-macro-rules.rs b/src/test/compile-fail/user-defined-macro-rules.rs index d55cef434f8d3..02e1a585fa89d 100644 --- a/src/test/compile-fail/user-defined-macro-rules.rs +++ b/src/test/compile-fail/user-defined-macro-rules.rs @@ -8,4 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(unused_macros)] + macro_rules! macro_rules { () => {} } //~ ERROR user-defined macros may not be named `macro_rules` From 0d0cb2796b99ea72fefd7d5759e097a6c529274a Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 14 May 2017 05:06:21 +0200 Subject: [PATCH 6/8] librustc_incremental: remove unused macro in test case --- .../persist/preds/compress/test_macro.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/librustc_incremental/persist/preds/compress/test_macro.rs b/src/librustc_incremental/persist/preds/compress/test_macro.rs index 31b30d2b2857c..044b143e30625 100644 --- a/src/librustc_incremental/persist/preds/compress/test_macro.rs +++ b/src/librustc_incremental/persist/preds/compress/test_macro.rs @@ -37,14 +37,3 @@ macro_rules! graph { } } } - -macro_rules! set { - ($( $value:expr ),*) => { - { - use $crate::rustc_data_structures::fx::FxHashSet; - let mut set = FxHashSet(); - $(set.insert($value);)* - set - } - } -} From 25b7f10c781fae5682523c59a73c4c6b49c97091 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 15 May 2017 07:35:19 +0200 Subject: [PATCH 7/8] Address review comments --- src/librustc_resolve/lib.rs | 10 ++++------ src/librustc_resolve/macros.rs | 14 +++++++------- src/libsyntax/ext/tt/macro_rules.rs | 6 ++---- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f78dd4890e2ce..827d902de02d1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1195,11 +1195,9 @@ pub struct Resolver<'a> { pub whitelisted_legacy_custom_derives: Vec, pub found_unresolved_macro: bool, - // List of macros that we need to warn about as being unused. - // The bool is true if the macro is unused, and false if its used. - // Setting a bool to false should be much faster than removing a single - // element from a FxHashSet. - unused_macros: FxHashMap, + // List of crate local macros that we need to warn about as being unused. + // Right now this only includes macro_rules! macros. + unused_macros: FxHashSet, // Maps the `Mark` of an expansion to its containing module or block. invocations: FxHashMap>, @@ -1406,7 +1404,7 @@ impl<'a> Resolver<'a> { potentially_unused_imports: Vec::new(), struct_constructors: DefIdMap(), found_unresolved_macro: false, - unused_macros: FxHashMap(), + unused_macros: FxHashSet(), } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index f6155c6cafdea..231d30cd2a22d 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -291,24 +291,24 @@ impl<'a> base::Resolver for Resolver<'a> { }, }; self.macro_defs.insert(invoc.expansion_data.mark, def.def_id()); - self.unused_macros.get_mut(&def.def_id()).map(|m| *m = false); + self.unused_macros.remove(&def.def_id()); Ok(Some(self.get_macro(def))) } fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) -> Result, Determinacy> { self.resolve_macro_to_def(scope, path, kind, force).map(|def| { - self.unused_macros.get_mut(&def.def_id()).map(|m| *m = false); + self.unused_macros.remove(&def.def_id()); self.get_macro(def) }) } fn check_unused_macros(&self) { - for (did, _) in self.unused_macros.iter().filter(|&(_, b)| *b) { + for did in self.unused_macros.iter() { let id_span = match *self.macro_map[did] { - SyntaxExtension::NormalTT(_, isp, _) => isp, - _ => None - }; + SyntaxExtension::NormalTT(_, isp, _) => isp, + _ => None, + }; if let Some((id, span)) = id_span { let lint = lint::builtin::UNUSED_MACROS; let msg = "unused macro definition".to_string(); @@ -708,7 +708,7 @@ impl<'a> Resolver<'a> { let def = Def::Macro(def_id, MacroKind::Bang); self.macro_exports.push(Export { name: ident.name, def: def, span: item.span }); } else { - self.unused_macros.insert(def_id, true); + self.unused_macros.insert(def_id); } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 0c787dcbecb9a..39a60e5c08010 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -252,11 +252,9 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) valid: valid, }); - NormalTT( - exp, + NormalTT(exp, Some((def.id, def.span)), - attr::contains_name(&def.attrs, "allow_internal_unstable") - ) + attr::contains_name(&def.attrs, "allow_internal_unstable")) } fn check_lhs_nt_follows(sess: &ParseSess, From 6dbd706906d922ae5606eb5654dd804095ffc8c8 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 16 May 2017 08:53:02 +0200 Subject: [PATCH 8/8] put option_try macro def under #[cfg(unix)] --- src/librustc/util/common.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 7b5e2253109aa..17564671a1e36 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -116,6 +116,7 @@ pub fn record_time(accu: &Cell, f: F) -> T where } // Like std::macros::try!, but for Option<>. +#[cfg(unix)] macro_rules! option_try( ($e:expr) => (match $e { Some(e) => e, None => return None }) );