From c2c0641444bac053188ff792eaa21c6ce8b2a690 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Fri, 5 May 2017 14:42:39 -0400 Subject: [PATCH 01/12] Add Vec::resize_default. --- src/doc/unstable-book/src/SUMMARY.md | 1 + .../library-features/vec-resize-default.md | 7 + src/libcollections/vec.rs | 128 +++++++++++++----- 3 files changed, 103 insertions(+), 33 deletions(-) create mode 100644 src/doc/unstable-book/src/library-features/vec-resize-default.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 3d9e7c7fd860..b978ce6b22be 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -217,6 +217,7 @@ - [unique](library-features/unique.md) - [unsize](library-features/unsize.md) - [utf8_error_error_len](library-features/utf8-error-error-len.md) + - [vec_resize_default](library-features/vec-resize-default.md) - [vec_remove_item](library-features/vec-remove-item.md) - [windows_c](library-features/windows-c.md) - [windows_handle](library-features/windows-handle.md) diff --git a/src/doc/unstable-book/src/library-features/vec-resize-default.md b/src/doc/unstable-book/src/library-features/vec-resize-default.md new file mode 100644 index 000000000000..5803d3215a54 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/vec-resize-default.md @@ -0,0 +1,7 @@ +# `vec_resize_default` + +The tracking issue for this feature is: [#41758] + +[#41758]: https://github.com/rust-lang/rust/issues/41758 + +------------------------ diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 7ec5c29de6b4..1cf713290d8e 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1220,11 +1220,14 @@ impl Vec { } impl Vec { - /// Resizes the `Vec` in-place so that `len()` is equal to `new_len`. + /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. /// - /// If `new_len` is greater than `len()`, the `Vec` is extended by the + /// If `new_len` is greater than `len`, the `Vec` is extended by the /// difference, with each additional slot filled with `value`. - /// If `new_len` is less than `len()`, the `Vec` is simply truncated. + /// If `new_len` is less than `len`, the `Vec` is simply truncated. + /// + /// This method requires `Clone` to clone the passed value. If you'd + /// rather create a value with `Default` instead, see [`resize_default`]. /// /// # Examples /// @@ -1237,19 +1240,100 @@ impl Vec { /// vec.resize(2, 0); /// assert_eq!(vec, [1, 2]); /// ``` + /// + /// [`resize_default`]: #method.resize_default #[stable(feature = "vec_resize", since = "1.5.0")] pub fn resize(&mut self, new_len: usize, value: T) { let len = self.len(); if new_len > len { - self.extend_with_element(new_len - len, value); + self.extend_with(new_len - len, ExtendElement(value)) + } else { + self.truncate(new_len); + } + } + + /// Clones and appends all elements in a slice to the `Vec`. + /// + /// Iterates over the slice `other`, clones each element, and then appends + /// it to this `Vec`. The `other` vector is traversed in-order. + /// + /// Note that this function is same as `extend` except that it is + /// specialized to work with slices instead. If and when Rust gets + /// specialization this function will likely be deprecated (but still + /// available). + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1]; + /// vec.extend_from_slice(&[2, 3, 4]); + /// assert_eq!(vec, [1, 2, 3, 4]); + /// ``` + #[stable(feature = "vec_extend_from_slice", since = "1.6.0")] + pub fn extend_from_slice(&mut self, other: &[T]) { + self.spec_extend(other.iter()) + } +} + +impl Vec { + /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. + /// + /// If `new_len` is greater than `len`, the `Vec` is extended by the + /// difference, with each additional slot filled with `Default::default()`. + /// If `new_len` is less than `len`, the `Vec` is simply truncated. + /// + /// This method uses `Default` to create new values on every push. If + /// you'd rather `Clone` a given value, use [`resize`]. + /// + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_resize_default)] + /// + /// let mut vec = vec![1, 2, 3]; + /// vec.resize_default(5); + /// assert_eq!(vec, [1, 2, 3, 0, 0]); + /// + /// let mut vec = vec![1, 2, 3, 4]; + /// vec.resize_default(2); + /// assert_eq!(vec, [1, 2]); + /// ``` + /// + /// [`resize`]: #method.resize + #[unstable(feature = "vec_resize_default", issue = "41758")] + pub fn resize_default(&mut self, new_len: usize) { + let len = self.len(); + + if new_len > len { + self.extend_with(new_len - len, ExtendDefault); } else { self.truncate(new_len); } } +} - /// Extend the vector by `n` additional clones of `value`. - fn extend_with_element(&mut self, n: usize, value: T) { +// This code generalises `extend_with_{element,default}`. +trait ExtendWith { + fn next(&self) -> T; + fn last(self) -> T; +} + +struct ExtendElement(T); +impl ExtendWith for ExtendElement { + fn next(&self) -> T { self.0.clone() } + fn last(self) -> T { self.0 } +} + +struct ExtendDefault; +impl ExtendWith for ExtendDefault { + fn next(&self) -> T { Default::default() } + fn last(self) -> T { Default::default() } +} +impl Vec { + /// Extend the vector by `n` values, using the given generator. + fn extend_with>(&mut self, n: usize, value: E) { self.reserve(n); unsafe { @@ -1261,43 +1345,21 @@ impl Vec { // Write all elements except the last one for _ in 1..n { - ptr::write(ptr, value.clone()); + ptr::write(ptr, value.next()); ptr = ptr.offset(1); - // Increment the length in every step in case clone() panics + // Increment the length in every step in case next() panics local_len.increment_len(1); } if n > 0 { // We can write the last element directly without cloning needlessly - ptr::write(ptr, value); + ptr::write(ptr, value.last()); local_len.increment_len(1); } // len set by scope guard } } - - /// Clones and appends all elements in a slice to the `Vec`. - /// - /// Iterates over the slice `other`, clones each element, and then appends - /// it to this `Vec`. The `other` vector is traversed in-order. - /// - /// Note that this function is same as `extend` except that it is - /// specialized to work with slices instead. If and when Rust gets - /// specialization this function will likely be deprecated (but still - /// available). - /// - /// # Examples - /// - /// ``` - /// let mut vec = vec![1]; - /// vec.extend_from_slice(&[2, 3, 4]); - /// assert_eq!(vec, [1, 2, 3, 4]); - /// ``` - #[stable(feature = "vec_extend_from_slice", since = "1.6.0")] - pub fn extend_from_slice(&mut self, other: &[T]) { - self.spec_extend(other.iter()) - } } // Set the length of the vec when the `SetLenOnDrop` value goes out of scope. @@ -1389,7 +1451,7 @@ trait SpecFromElem: Sized { impl SpecFromElem for T { default fn from_elem(elem: Self, n: usize) -> Vec { let mut v = Vec::with_capacity(n); - v.extend_with_element(n, elem); + v.extend_with(n, ExtendElement(elem)); v } } @@ -1424,7 +1486,7 @@ macro_rules! impl_spec_from_elem { } } let mut v = Vec::with_capacity(n); - v.extend_with_element(n, elem); + v.extend_with(n, ExtendElement(elem)); v } } From df188b8f976a49c226068e42a6c3ae2e15956daf Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 11 May 2017 10:26:07 +0200 Subject: [PATCH 02/12] 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 e681d55cf94b..07140f71aeba 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 8fddbe110b0e..eff5d2b2f37f 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 2d0b5a6a51c6..479c7206cb4c 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 c4512cb38c4e..f78dd4890e2c 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 c08421cb9374..29ca163b0b4b 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 f731c5abdd6a..b0253ec3905c 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 03/12] 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 2e42c6986e64..1855681221b8 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 04/12] 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 6f3e84247f79..172b74d53933 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 cdde56f5f634..3027489d65be 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 29ca163b0b4b..f6155c6cafde 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 b0253ec3905c..86202f77dbf8 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 a8aa103f80a8..75dd09f23115 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 f959ccc989e2..0c787dcbecb9 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 05/12] 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 013f02685bad..6cc374b13b7b 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 391b606f613f..ca6438c0fa71 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 06/12] 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 e0066dd43be8..ddd8631f02e6 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 1aabe6b87dff..9af501b14195 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 8a2d8dddac07..61a362cb37fb 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 a0ac5d4c7204..d710f5647dd9 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 fefd432e2298..f66c09291cc9 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 6994d2199d27..15eef429eab9 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 0168ae7d9101..8b49772494a6 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 1c543a5fdacb..267362f902d7 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 ada06b0b3f45..06f2d86e5d9b 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 001bc42274b4..6e80e9b574bc 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 0ee2221bbc14..21cc946ded60 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 fe758a4a6310..e5fdba63b0f1 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 8381dc34a6a1..f5e7305e4ea9 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 b868b79365d9..28a69e6f9e29 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 e9d09bb6ad9c..dda0d3fc9557 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 000000000000..5e401c09bda5 --- /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 d55cef434f8d..02e1a585fa89 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 07/12] 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 31b30d2b2857..044b143e3062 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 a9cb094879fabd23774a0d9dcfed7f3eeb9a4aff Mon Sep 17 00:00:00 2001 From: Felix Raimundo Date: Sat, 13 May 2017 21:42:51 +0200 Subject: [PATCH 08/12] Explain why `thread::yield_now` could be used. Part of #29378. --- src/libstd/thread/mod.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 200368be275c..8f1a88ed3051 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -468,6 +468,23 @@ pub fn current() -> Thread { /// Cooperatively gives up a timeslice to the OS scheduler. /// +/// This is used when the programmer knows that the thread will have nothing +/// to do for some time, and thus avoid wasting computing time. +/// +/// For example when polling on a resource, it is common to check that it is +/// available, and if not to yield in order to avoid busy waiting. +/// +/// Thus the pattern of `yield`ing after a failed poll is rather common when +/// implementing low-level shared resources or synchronization primitives. +/// +/// However programmers will usualy prefer to use, [`channel`]s, [`Condvar`]s, +/// [`Mutex`]es or [`join`] for their synchronisation routines, as they avoid +/// thinking about thread schedulling. +/// +/// Note that [`channel`]s for example are implemented using this primitive. +/// Indeed when you call `send` or `recv`, which are blocking, they will yield +/// if the channel is not available. +/// /// # Examples /// /// ``` @@ -475,6 +492,12 @@ pub fn current() -> Thread { /// /// thread::yield_now(); /// ``` +/// +/// [`channel`]: ../../std/sync/mpsc/index.html +/// [`spawn`]: ../../std/thread/fn.spawn.html +/// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join +/// [`Mutex`]: ../../std/sync/struct.Mutex.html +/// [`Condvar`]: ../../std/sync/struct.Condvar.html #[stable(feature = "rust1", since = "1.0.0")] pub fn yield_now() { imp::Thread::yield_now() From a51777ec874e31b29d85efaa186fe4841257b168 Mon Sep 17 00:00:00 2001 From: Felix Raimundo Date: Sun, 14 May 2017 19:35:36 +0200 Subject: [PATCH 09/12] Improve `thread::Builder` documentation. Part of #29378 . - In particular explains *why* we would use the builder instead of the free function. - Changes the parent-child explanation for a spawned-caller. - Add link to `io::Result` in `thread::Builder` - Corrects the `thread::Builder::spawn` documentation. --- src/libstd/thread/mod.rs | 49 +++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 200368be275c..1f079c21f577 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -180,8 +180,33 @@ pub use self::local::{LocalKey, LocalKeyState}; // Builder //////////////////////////////////////////////////////////////////////////////// -/// Thread configuration. Provides detailed control over the properties -/// and behavior of new threads. +/// Thread factory, which can be used in order to configure the properties of +/// a new thread. +/// +/// Methods can be chained on it in order to configure it. +/// +/// The two configurations available are: +/// +/// - [`name`]: allows to give a name to the thread which is currently +/// only used in `panic` messages. +/// - [`stack_size`]: specifies the desired stack size. Note that this can +/// be overriden by the OS. +/// +/// If the [`stack_size`] field is not specified, the stack size +/// will be the `RUST_MIN_STACK` environment variable. If it is +/// not specified either, a sensible default will be set. +/// +/// If the [`name`] field is not specified, the thread will not be named. +/// +/// The [`spawn`] method will take ownership of the builder and create an +/// [`io::Result`] to the thread handle with the given configuration. +/// +/// The [`thread::spawn`] free function uses a `Builder` with default +/// configuration and [`unwrap`]s its return value. +/// +/// You may want to use [`spawn`] instead of [`thread::spawn`], when you want +/// to recover from a failure to launch a thread, indeed the free function will +/// panick where the `Builder` method will return a [`io::Result`]. /// /// # Examples /// @@ -196,6 +221,13 @@ pub use self::local::{LocalKey, LocalKeyState}; /// /// handler.join().unwrap(); /// ``` +/// +/// [`thread::spawn`]: ../../std/thread/fn.spawn.html +/// [`stack_size`]: ../../std/thread/struct.Builder.html#method.stack_size +/// [`name`]: ../../std/thread/struct.Builder.html#method.name +/// [`spawn`]: ../../std/thread/struct.Builder.html#method.spawn +/// [`io::Result`]: ../../std/io/type.Result.html +/// [`unwrap`]: ../../std/result/enum.Result.html#method.unwrap #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Builder { @@ -209,11 +241,6 @@ impl Builder { /// Generates the base configuration for spawning a thread, from which /// configuration methods can be chained. /// - /// If the [`stack_size`] field is not specified, the stack size - /// will be the `RUST_MIN_STACK` environment variable. If it is - /// not specified either, a sensible default will be set (2MB as - /// of the writting of this doc). - /// /// # Examples /// /// ``` @@ -229,8 +256,6 @@ impl Builder { /// /// handler.join().unwrap(); /// ``` - /// - /// [`stack_size`]: ../../std/thread/struct.Builder.html#method.stack_size #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Builder { Builder { @@ -280,9 +305,10 @@ impl Builder { self } - /// Spawns a new thread, and returns a join handle for it. + /// Spawns a new thread by taking ownership of the `Builder`, and returns an + /// [`io::Result`] to its [`JoinHandle`]. /// - /// The child thread may outlive the parent (unless the parent thread + /// The spawned thread may outlive the caller (unless the caller thread /// is the main thread; the whole process is terminated when the main /// thread finishes). The join handle can be used to block on /// termination of the child thread, including recovering its panics. @@ -297,6 +323,7 @@ impl Builder { /// /// [`spawn`]: ../../std/thread/fn.spawn.html /// [`io::Result`]: ../../std/io/type.Result.html + /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html /// /// # Examples /// From c0d5aa8aaf478e52d0e96bd0fbd19cde6e30ebb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 23 Apr 2017 17:57:07 -0700 Subject: [PATCH 10/12] Make unsatisfied trait bounds note multiline Make diagnostic note for existing method with unsatisfied trait bounds multiline for cleaner output. ``` = note: the method `count` exists but the following trait bounds were not satisfied: `[closure@../../src/test/compile-fail/issue-36053-2.rs:17:39: 17:53] : std::ops::FnMut<(&_,)>` `std::iter::Filter> [closure@../../src/test/compile-fail/issue-36053-2.rs:17:39: 17:53]> : std::iter::Iterator` Before: ``` = note: the method `count` exists but the following trait bounds were not satisfied: `[closure@../../src/test/compile-fail/issue-36053-2.rs:17:39: 17:53] : std::ops::FnMut<(&_,)>`, `std::iter::Filter>, [closure@../../src/test/compile-fail/issue-36053-2.rs:17:39: 17:53]> : std::iter::Iterator` ``` --- src/librustc_typeck/check/method/suggest.rs | 4 ++-- src/test/ui/mismatched_types/issue-36053-2.stderr | 4 +++- .../method-help-unsatisfied-bound.rs | 2 +- .../method-help-unsatisfied-bound.stderr | 11 +++++++++++ 4 files changed, 17 insertions(+), 4 deletions(-) rename src/test/{compile-fail => ui/mismatched_types}/method-help-unsatisfied-bound.rs (87%) create mode 100644 src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index c7ec379b0de2..7e70bb92cd6e 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -251,9 +251,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let bound_list = unsatisfied_predicates.iter() .map(|p| format!("`{} : {}`", p.self_ty(), p)) .collect::>() - .join(", "); + .join("\n"); err.note(&format!("the method `{}` exists but the following trait bounds \ - were not satisfied: {}", + were not satisfied:\n{}", item_name, bound_list)); } diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index adc229aaacc5..78e0f7e619b1 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -4,7 +4,9 @@ error: no method named `count` found for type `std::iter::Filter("str").fuse().filter(|a: &str| true).count(); | ^^^^^ | - = note: the method `count` exists but the following trait bounds were not satisfied: `[closure@$DIR/issue-36053-2.rs:17:39: 17:53] : std::ops::FnMut<(&_,)>`, `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:17:39: 17:53]> : std::iter::Iterator` + = note: the method `count` exists but the following trait bounds were not satisfied: + `[closure@$DIR/issue-36053-2.rs:17:39: 17:53] : std::ops::FnMut<(&_,)>` + `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:17:39: 17:53]> : std::iter::Iterator` error[E0281]: type mismatch: `[closure@$DIR/issue-36053-2.rs:17:39: 17:53]` implements the trait `for<'r> std::ops::FnMut<(&'r str,)>`, but the trait `for<'r> std::ops::FnMut<(&'r &str,)>` is required --> $DIR/issue-36053-2.rs:17:32 diff --git a/src/test/compile-fail/method-help-unsatisfied-bound.rs b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.rs similarity index 87% rename from src/test/compile-fail/method-help-unsatisfied-bound.rs rename to src/test/ui/mismatched_types/method-help-unsatisfied-bound.rs index 6416d5467c89..a4eb44555511 100644 --- a/src/test/compile-fail/method-help-unsatisfied-bound.rs +++ b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.rs @@ -14,5 +14,5 @@ fn main() { let a: Result<(), Foo> = Ok(()); a.unwrap(); //~^ ERROR no method named `unwrap` found for type `std::result::Result<(), Foo>` - //~| NOTE the following trait bounds were not satisfied: `Foo : std::fmt::Debug` + //~| NOTE the method `unwrap` exists but the following trait bounds were not satisfied } diff --git a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr new file mode 100644 index 000000000000..2bd786c20fef --- /dev/null +++ b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr @@ -0,0 +1,11 @@ +error: no method named `unwrap` found for type `std::result::Result<(), Foo>` in the current scope + --> $DIR/method-help-unsatisfied-bound.rs:15:7 + | +15 | a.unwrap(); + | ^^^^^^ + | + = note: the method `unwrap` exists but the following trait bounds were not satisfied: + `Foo : std::fmt::Debug` + +error: aborting due to previous error + From 25b7f10c781fae5682523c59a73c4c6b49c97091 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 15 May 2017 07:35:19 +0200 Subject: [PATCH 11/12] 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 f78dd4890e2c..827d902de02d 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 f6155c6cafde..231d30cd2a22 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 0c787dcbecb9..39a60e5c0801 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 f92bd3dbd005bb0bbcdeb64eea263634428d660a Mon Sep 17 00:00:00 2001 From: Felix Raimundo Date: Sun, 14 May 2017 20:06:54 +0200 Subject: [PATCH 12/12] Add links to the `thread::LocalKey` doc. Part of #29378 . --- src/libstd/thread/local.rs | 45 +++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index e2b22b1d89f0..c2c6e6cf87df 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -19,16 +19,16 @@ use mem; /// A thread local storage key which owns its contents. /// /// This key uses the fastest possible implementation available to it for the -/// target platform. It is instantiated with the `thread_local!` macro and the -/// primary method is the `with` method. +/// target platform. It is instantiated with the [`thread_local!`] macro and the +/// primary method is the [`with`] method. /// -/// The `with` method yields a reference to the contained value which cannot be +/// The [`with`] method yields a reference to the contained value which cannot be /// sent across threads or escape the given closure. /// /// # Initialization and Destruction /// -/// Initialization is dynamically performed on the first call to `with()` -/// within a thread, and values that implement `Drop` get destructed when a +/// Initialization is dynamically performed on the first call to [`with`] +/// within a thread, and values that implement [`Drop`] get destructed when a /// thread exits. Some caveats apply, which are explained below. /// /// # Examples @@ -77,6 +77,10 @@ use mem; /// 3. On macOS, initializing TLS during destruction of other TLS slots can /// sometimes cancel *all* destructors for the current thread, whether or not /// the slots have already had their destructors run or not. +/// +/// [`with`]: ../../std/thread/struct.LocalKey.html#method.with +/// [`thread_local!`]: ../../std/macro.thread_local.html +/// [`Drop`]: ../../std/ops/trait.Drop.html #[stable(feature = "rust1", since = "1.0.0")] pub struct LocalKey { // This outer `LocalKey` type is what's going to be stored in statics, @@ -106,7 +110,7 @@ impl fmt::Debug for LocalKey { } } -/// Declare a new thread local storage key of type `std::thread::LocalKey`. +/// Declare a new thread local storage key of type [`std::thread::LocalKey`]. /// /// # Syntax /// @@ -124,8 +128,10 @@ impl fmt::Debug for LocalKey { /// # fn main() {} /// ``` /// -/// See [LocalKey documentation](thread/struct.LocalKey.html) for more +/// See [LocalKey documentation][`std::thread::LocalKey`] for more /// information. +/// +/// [`std::thread::LocalKey`]: ../std/thread/struct.LocalKey.html #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable] @@ -195,11 +201,13 @@ macro_rules! __thread_local_inner { #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub enum LocalKeyState { /// All keys are in this state whenever a thread starts. Keys will - /// transition to the `Valid` state once the first call to `with` happens + /// transition to the `Valid` state once the first call to [`with`] happens /// and the initialization expression succeeds. /// /// Keys in the `Uninitialized` state will yield a reference to the closure - /// passed to `with` so long as the initialization routine does not panic. + /// passed to [`with`] so long as the initialization routine does not panic. + /// + /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with Uninitialized, /// Once a key has been accessed successfully, it will enter the `Valid` @@ -208,7 +216,9 @@ pub enum LocalKeyState { /// `Destroyed` state. /// /// Keys in the `Valid` state will be guaranteed to yield a reference to the - /// closure passed to `with`. + /// closure passed to [`with`]. + /// + /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with Valid, /// When a thread exits, the destructors for keys will be run (if @@ -216,7 +226,9 @@ pub enum LocalKeyState { /// destructor has run, a key is in the `Destroyed` state. /// /// Keys in the `Destroyed` states will trigger a panic when accessed via - /// `with`. + /// [`with`]. + /// + /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with Destroyed, } @@ -283,23 +295,26 @@ impl LocalKey { /// Query the current state of this key. /// /// A key is initially in the `Uninitialized` state whenever a thread - /// starts. It will remain in this state up until the first call to `with` + /// starts. It will remain in this state up until the first call to [`with`] /// within a thread has run the initialization expression successfully. /// /// Once the initialization expression succeeds, the key transitions to the - /// `Valid` state which will guarantee that future calls to `with` will + /// `Valid` state which will guarantee that future calls to [`with`] will /// succeed within the thread. /// /// When a thread exits, each key will be destroyed in turn, and as keys are /// destroyed they will enter the `Destroyed` state just before the /// destructor starts to run. Keys may remain in the `Destroyed` state after /// destruction has completed. Keys without destructors (e.g. with types - /// that are `Copy`), may never enter the `Destroyed` state. + /// that are [`Copy`]), may never enter the `Destroyed` state. /// /// Keys in the `Uninitialized` state can be accessed so long as the /// initialization does not panic. Keys in the `Valid` state are guaranteed /// to be able to be accessed. Keys in the `Destroyed` state will panic on - /// any call to `with`. + /// any call to [`with`]. + /// + /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with + /// [`Copy`]: ../../std/marker/trait.Copy.html #[unstable(feature = "thread_local_state", reason = "state querying was recently added", issue = "27716")]