Auto merge of #96150 - est31:unused_macro_rules, r=petrochenkov
Implement a lint to warn about unused macro rules This implements a new lint to warn about unused macro rules (arms/matchers), similar to the `unused_macros` lint added by #41907 that warns about entire macros. ```rust macro_rules! unused_empty { (hello) => { println!("Hello, world!") }; () => { println!("empty") }; //~ ERROR: 1st rule of macro `unused_empty` is never used } fn main() { unused_empty!(hello); } ``` Builds upon #96149 and #96156. Fixes #73576
This commit is contained in:
commit
0cd939e36c
34 changed files with 400 additions and 78 deletions
|
@ -816,6 +816,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<&'ll Value, ()> {
|
) -> Result<&'ll Value, ()> {
|
||||||
// macros for error handling:
|
// macros for error handling:
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_macro_rules))]
|
||||||
macro_rules! emit_error {
|
macro_rules! emit_error {
|
||||||
($msg: tt) => {
|
($msg: tt) => {
|
||||||
emit_error!($msg, )
|
emit_error!($msg, )
|
||||||
|
@ -1144,6 +1145,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||||
span: Span,
|
span: Span,
|
||||||
args: &[OperandRef<'tcx, &'ll Value>],
|
args: &[OperandRef<'tcx, &'ll Value>],
|
||||||
) -> Result<&'ll Value, ()> {
|
) -> Result<&'ll Value, ()> {
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_macro_rules))]
|
||||||
macro_rules! emit_error {
|
macro_rules! emit_error {
|
||||||
($msg: tt) => {
|
($msg: tt) => {
|
||||||
emit_error!($msg, )
|
emit_error!($msg, )
|
||||||
|
|
|
@ -886,6 +886,8 @@ pub trait ResolverExpand {
|
||||||
force: bool,
|
force: bool,
|
||||||
) -> Result<Lrc<SyntaxExtension>, Indeterminate>;
|
) -> Result<Lrc<SyntaxExtension>, Indeterminate>;
|
||||||
|
|
||||||
|
fn record_macro_rule_usage(&mut self, mac_id: NodeId, rule_index: usize);
|
||||||
|
|
||||||
fn check_unused_macros(&mut self);
|
fn check_unused_macros(&mut self);
|
||||||
|
|
||||||
// Resolver interfaces for specific built-in macros.
|
// Resolver interfaces for specific built-in macros.
|
||||||
|
|
|
@ -156,13 +156,13 @@ impl<'a> ParserAnyMacro<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MacroRulesMacroExpander {
|
struct MacroRulesMacroExpander {
|
||||||
|
node_id: NodeId,
|
||||||
name: Ident,
|
name: Ident,
|
||||||
span: Span,
|
span: Span,
|
||||||
transparency: Transparency,
|
transparency: Transparency,
|
||||||
lhses: Vec<Vec<MatcherLoc>>,
|
lhses: Vec<Vec<MatcherLoc>>,
|
||||||
rhses: Vec<mbe::TokenTree>,
|
rhses: Vec<mbe::TokenTree>,
|
||||||
valid: bool,
|
valid: bool,
|
||||||
is_local: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TTMacroExpander for MacroRulesMacroExpander {
|
impl TTMacroExpander for MacroRulesMacroExpander {
|
||||||
|
@ -179,12 +179,12 @@ impl TTMacroExpander for MacroRulesMacroExpander {
|
||||||
cx,
|
cx,
|
||||||
sp,
|
sp,
|
||||||
self.span,
|
self.span,
|
||||||
|
self.node_id,
|
||||||
self.name,
|
self.name,
|
||||||
self.transparency,
|
self.transparency,
|
||||||
input,
|
input,
|
||||||
&self.lhses,
|
&self.lhses,
|
||||||
&self.rhses,
|
&self.rhses,
|
||||||
self.is_local,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,14 +207,17 @@ fn generic_extension<'cx, 'tt>(
|
||||||
cx: &'cx mut ExtCtxt<'_>,
|
cx: &'cx mut ExtCtxt<'_>,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
def_span: Span,
|
def_span: Span,
|
||||||
|
node_id: NodeId,
|
||||||
name: Ident,
|
name: Ident,
|
||||||
transparency: Transparency,
|
transparency: Transparency,
|
||||||
arg: TokenStream,
|
arg: TokenStream,
|
||||||
lhses: &'tt [Vec<MatcherLoc>],
|
lhses: &'tt [Vec<MatcherLoc>],
|
||||||
rhses: &'tt [mbe::TokenTree],
|
rhses: &'tt [mbe::TokenTree],
|
||||||
is_local: bool,
|
|
||||||
) -> Box<dyn MacResult + 'cx> {
|
) -> Box<dyn MacResult + 'cx> {
|
||||||
let sess = &cx.sess.parse_sess;
|
let sess = &cx.sess.parse_sess;
|
||||||
|
// Macros defined in the current crate have a real node id,
|
||||||
|
// whereas macros from an external crate have a dummy id.
|
||||||
|
let is_local = node_id != DUMMY_NODE_ID;
|
||||||
|
|
||||||
if cx.trace_macros() {
|
if cx.trace_macros() {
|
||||||
let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(&arg));
|
let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(&arg));
|
||||||
|
@ -296,6 +299,10 @@ fn generic_extension<'cx, 'tt>(
|
||||||
let mut p = Parser::new(sess, tts, false, None);
|
let mut p = Parser::new(sess, tts, false, None);
|
||||||
p.last_type_ascription = cx.current_expansion.prior_type_ascription;
|
p.last_type_ascription = cx.current_expansion.prior_type_ascription;
|
||||||
|
|
||||||
|
if is_local {
|
||||||
|
cx.resolver.record_macro_rule_usage(node_id, i);
|
||||||
|
}
|
||||||
|
|
||||||
// Let the context choose how to interpret the result.
|
// Let the context choose how to interpret the result.
|
||||||
// Weird, but useful for X-macros.
|
// Weird, but useful for X-macros.
|
||||||
return Box::new(ParserAnyMacro {
|
return Box::new(ParserAnyMacro {
|
||||||
|
@ -372,7 +379,7 @@ pub fn compile_declarative_macro(
|
||||||
features: &Features,
|
features: &Features,
|
||||||
def: &ast::Item,
|
def: &ast::Item,
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
) -> SyntaxExtension {
|
) -> (SyntaxExtension, Vec<Span>) {
|
||||||
debug!("compile_declarative_macro: {:?}", def);
|
debug!("compile_declarative_macro: {:?}", def);
|
||||||
let mk_syn_ext = |expander| {
|
let mk_syn_ext = |expander| {
|
||||||
SyntaxExtension::new(
|
SyntaxExtension::new(
|
||||||
|
@ -385,6 +392,7 @@ pub fn compile_declarative_macro(
|
||||||
&def.attrs,
|
&def.attrs,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
let dummy_syn_ext = || (mk_syn_ext(Box::new(macro_rules_dummy_expander)), Vec::new());
|
||||||
|
|
||||||
let diag = &sess.parse_sess.span_diagnostic;
|
let diag = &sess.parse_sess.span_diagnostic;
|
||||||
let lhs_nm = Ident::new(sym::lhs, def.span);
|
let lhs_nm = Ident::new(sym::lhs, def.span);
|
||||||
|
@ -445,17 +453,17 @@ pub fn compile_declarative_macro(
|
||||||
let s = parse_failure_msg(&token);
|
let s = parse_failure_msg(&token);
|
||||||
let sp = token.span.substitute_dummy(def.span);
|
let sp = token.span.substitute_dummy(def.span);
|
||||||
sess.parse_sess.span_diagnostic.struct_span_err(sp, &s).span_label(sp, msg).emit();
|
sess.parse_sess.span_diagnostic.struct_span_err(sp, &s).span_label(sp, msg).emit();
|
||||||
return mk_syn_ext(Box::new(macro_rules_dummy_expander));
|
return dummy_syn_ext();
|
||||||
}
|
}
|
||||||
Error(sp, msg) => {
|
Error(sp, msg) => {
|
||||||
sess.parse_sess
|
sess.parse_sess
|
||||||
.span_diagnostic
|
.span_diagnostic
|
||||||
.struct_span_err(sp.substitute_dummy(def.span), &msg)
|
.struct_span_err(sp.substitute_dummy(def.span), &msg)
|
||||||
.emit();
|
.emit();
|
||||||
return mk_syn_ext(Box::new(macro_rules_dummy_expander));
|
return dummy_syn_ext();
|
||||||
}
|
}
|
||||||
ErrorReported => {
|
ErrorReported => {
|
||||||
return mk_syn_ext(Box::new(macro_rules_dummy_expander));
|
return dummy_syn_ext();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -530,6 +538,15 @@ pub fn compile_declarative_macro(
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compute the spans of the macro rules
|
||||||
|
// We only take the span of the lhs here,
|
||||||
|
// so that the spans of created warnings are smaller.
|
||||||
|
let rule_spans = if def.id != DUMMY_NODE_ID {
|
||||||
|
lhses.iter().map(|lhs| lhs.span()).collect::<Vec<_>>()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
// Convert the lhses into `MatcherLoc` form, which is better for doing the
|
// Convert the lhses into `MatcherLoc` form, which is better for doing the
|
||||||
// actual matching. Unless the matcher is invalid.
|
// actual matching. Unless the matcher is invalid.
|
||||||
let lhses = if valid {
|
let lhses = if valid {
|
||||||
|
@ -549,17 +566,16 @@ pub fn compile_declarative_macro(
|
||||||
vec![]
|
vec![]
|
||||||
};
|
};
|
||||||
|
|
||||||
mk_syn_ext(Box::new(MacroRulesMacroExpander {
|
let expander = Box::new(MacroRulesMacroExpander {
|
||||||
name: def.ident,
|
name: def.ident,
|
||||||
span: def.span,
|
span: def.span,
|
||||||
|
node_id: def.id,
|
||||||
transparency,
|
transparency,
|
||||||
lhses,
|
lhses,
|
||||||
rhses,
|
rhses,
|
||||||
valid,
|
valid,
|
||||||
// Macros defined in the current crate have a real node id,
|
});
|
||||||
// whereas macros from an external crate have a dummy id.
|
(mk_syn_ext(expander), rule_spans)
|
||||||
is_local: def.id != DUMMY_NODE_ID,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree) -> bool {
|
fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree) -> bool {
|
||||||
|
|
|
@ -303,6 +303,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
|
||||||
PATH_STATEMENTS,
|
PATH_STATEMENTS,
|
||||||
UNUSED_ATTRIBUTES,
|
UNUSED_ATTRIBUTES,
|
||||||
UNUSED_MACROS,
|
UNUSED_MACROS,
|
||||||
|
UNUSED_MACRO_RULES,
|
||||||
UNUSED_ALLOCATION,
|
UNUSED_ALLOCATION,
|
||||||
UNUSED_DOC_COMMENTS,
|
UNUSED_DOC_COMMENTS,
|
||||||
UNUSED_EXTERN_CRATES,
|
UNUSED_EXTERN_CRATES,
|
||||||
|
|
|
@ -749,6 +749,10 @@ declare_lint! {
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `unused_macros` lint detects macros that were not used.
|
/// The `unused_macros` lint detects macros that were not used.
|
||||||
///
|
///
|
||||||
|
/// Note that this lint is distinct from the `unused_macro_rules` lint,
|
||||||
|
/// which checks for single rules that never match of an otherwise used
|
||||||
|
/// macro, and thus never expand.
|
||||||
|
///
|
||||||
/// ### Example
|
/// ### Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
|
@ -775,6 +779,45 @@ declare_lint! {
|
||||||
"detects macros that were not used"
|
"detects macros that were not used"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `unused_macro_rules` lint detects macro rules that were not used.
|
||||||
|
///
|
||||||
|
/// Note that the lint is distinct from the `unused_macros` lint, which
|
||||||
|
/// fires if the entire macro is never called, while this lint fires for
|
||||||
|
/// single unused rules of the macro that is otherwise used.
|
||||||
|
/// `unused_macro_rules` fires only if `unused_macros` wouldn't fire.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// macro_rules! unused_empty {
|
||||||
|
/// (hello) => { println!("Hello, world!") }; // This rule is unused
|
||||||
|
/// () => { println!("empty") }; // This rule is used
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// unused_empty!(hello);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// Unused macro rules may signal a mistake or unfinished code. Furthermore,
|
||||||
|
/// they slow down compilation. Right now, silencing the warning is not
|
||||||
|
/// supported on a single rule level, so you have to add an allow to the
|
||||||
|
/// entire macro definition.
|
||||||
|
///
|
||||||
|
/// If you intended to export the macro to make it
|
||||||
|
/// available outside of the crate, use the [`macro_export` attribute].
|
||||||
|
///
|
||||||
|
/// [`macro_export` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope
|
||||||
|
pub UNUSED_MACRO_RULES,
|
||||||
|
Warn,
|
||||||
|
"detects macro rules that were not used"
|
||||||
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `warnings` lint allows you to change the level of other
|
/// The `warnings` lint allows you to change the level of other
|
||||||
/// lints which produce warnings.
|
/// lints which produce warnings.
|
||||||
|
@ -3104,6 +3147,7 @@ declare_lint_pass! {
|
||||||
OVERLAPPING_RANGE_ENDPOINTS,
|
OVERLAPPING_RANGE_ENDPOINTS,
|
||||||
BINDINGS_WITH_VARIANT_NAME,
|
BINDINGS_WITH_VARIANT_NAME,
|
||||||
UNUSED_MACROS,
|
UNUSED_MACROS,
|
||||||
|
UNUSED_MACRO_RULES,
|
||||||
WARNINGS,
|
WARNINGS,
|
||||||
UNUSED_FEATURES,
|
UNUSED_FEATURES,
|
||||||
STABLE_FEATURES,
|
STABLE_FEATURES,
|
||||||
|
|
|
@ -258,6 +258,7 @@ macro_rules! make_mir_visitor {
|
||||||
// for best performance, we want to use an iterator rather
|
// for best performance, we want to use an iterator rather
|
||||||
// than a for-loop, to avoid calling `body::Body::invalidate` for
|
// than a for-loop, to avoid calling `body::Body::invalidate` for
|
||||||
// each basic block.
|
// each basic block.
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_macro_rules))]
|
||||||
macro_rules! basic_blocks {
|
macro_rules! basic_blocks {
|
||||||
(mut) => (body.basic_blocks_mut().iter_enumerated_mut());
|
(mut) => (body.basic_blocks_mut().iter_enumerated_mut());
|
||||||
() => (body.basic_blocks().iter_enumerated());
|
() => (body.basic_blocks().iter_enumerated());
|
||||||
|
@ -279,6 +280,7 @@ macro_rules! make_mir_visitor {
|
||||||
self.visit_local_decl(local, & $($mutability)? body.local_decls[local]);
|
self.visit_local_decl(local, & $($mutability)? body.local_decls[local]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_macro_rules))]
|
||||||
macro_rules! type_annotations {
|
macro_rules! type_annotations {
|
||||||
(mut) => (body.user_type_annotations.iter_enumerated_mut());
|
(mut) => (body.user_type_annotations.iter_enumerated_mut());
|
||||||
() => (body.user_type_annotations.iter_enumerated());
|
() => (body.user_type_annotations.iter_enumerated());
|
||||||
|
@ -932,6 +934,7 @@ macro_rules! make_mir_visitor {
|
||||||
body: &$($mutability)? Body<'tcx>,
|
body: &$($mutability)? Body<'tcx>,
|
||||||
location: Location
|
location: Location
|
||||||
) {
|
) {
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_macro_rules))]
|
||||||
macro_rules! basic_blocks {
|
macro_rules! basic_blocks {
|
||||||
(mut) => (body.basic_blocks_mut());
|
(mut) => (body.basic_blocks_mut());
|
||||||
() => (body.basic_blocks());
|
() => (body.basic_blocks());
|
||||||
|
|
|
@ -4,7 +4,6 @@ version = "0.0.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
test = false
|
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
@ -194,7 +194,7 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let ext = Lrc::new(match self.cstore().load_macro_untracked(def_id, &self.session) {
|
let ext = Lrc::new(match self.cstore().load_macro_untracked(def_id, &self.session) {
|
||||||
LoadedMacro::MacroDef(item, edition) => self.compile_macro(&item, edition),
|
LoadedMacro::MacroDef(item, edition) => self.compile_macro(&item, edition).0,
|
||||||
LoadedMacro::ProcMacro(ext) => ext,
|
LoadedMacro::ProcMacro(ext) => ext,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1218,9 +1218,18 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
||||||
// Mark the given macro as unused unless its name starts with `_`.
|
// Mark the given macro as unused unless its name starts with `_`.
|
||||||
// Macro uses will remove items from this set, and the remaining
|
// Macro uses will remove items from this set, and the remaining
|
||||||
// items will be reported as `unused_macros`.
|
// items will be reported as `unused_macros`.
|
||||||
fn insert_unused_macro(&mut self, ident: Ident, def_id: LocalDefId, node_id: NodeId) {
|
fn insert_unused_macro(
|
||||||
|
&mut self,
|
||||||
|
ident: Ident,
|
||||||
|
def_id: LocalDefId,
|
||||||
|
node_id: NodeId,
|
||||||
|
rule_spans: &[Span],
|
||||||
|
) {
|
||||||
if !ident.as_str().starts_with('_') {
|
if !ident.as_str().starts_with('_') {
|
||||||
self.r.unused_macros.insert(def_id, (node_id, ident));
|
self.r.unused_macros.insert(def_id, (node_id, ident));
|
||||||
|
for (rule_i, rule_span) in rule_spans.iter().enumerate() {
|
||||||
|
self.r.unused_macro_rules.insert((def_id, rule_i), (ident, *rule_span));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1228,15 +1237,16 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
||||||
let parent_scope = self.parent_scope;
|
let parent_scope = self.parent_scope;
|
||||||
let expansion = parent_scope.expansion;
|
let expansion = parent_scope.expansion;
|
||||||
let def_id = self.r.local_def_id(item.id);
|
let def_id = self.r.local_def_id(item.id);
|
||||||
let (ext, ident, span, macro_rules) = match &item.kind {
|
let (ext, ident, span, macro_rules, rule_spans) = match &item.kind {
|
||||||
ItemKind::MacroDef(def) => {
|
ItemKind::MacroDef(def) => {
|
||||||
let ext = Lrc::new(self.r.compile_macro(item, self.r.session.edition()));
|
let (ext, rule_spans) = self.r.compile_macro(item, self.r.session.edition());
|
||||||
(ext, item.ident, item.span, def.macro_rules)
|
let ext = Lrc::new(ext);
|
||||||
|
(ext, item.ident, item.span, def.macro_rules, rule_spans)
|
||||||
}
|
}
|
||||||
ItemKind::Fn(..) => match self.proc_macro_stub(item) {
|
ItemKind::Fn(..) => match self.proc_macro_stub(item) {
|
||||||
Some((macro_kind, ident, span)) => {
|
Some((macro_kind, ident, span)) => {
|
||||||
self.r.proc_macro_stubs.insert(def_id);
|
self.r.proc_macro_stubs.insert(def_id);
|
||||||
(self.r.dummy_ext(macro_kind), ident, span, false)
|
(self.r.dummy_ext(macro_kind), ident, span, false, Vec::new())
|
||||||
}
|
}
|
||||||
None => return parent_scope.macro_rules,
|
None => return parent_scope.macro_rules,
|
||||||
},
|
},
|
||||||
|
@ -1264,7 +1274,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
||||||
self.r.define(module, ident, MacroNS, (res, vis, span, expansion, IsMacroExport));
|
self.r.define(module, ident, MacroNS, (res, vis, span, expansion, IsMacroExport));
|
||||||
} else {
|
} else {
|
||||||
self.r.check_reserved_macro_name(ident, res);
|
self.r.check_reserved_macro_name(ident, res);
|
||||||
self.insert_unused_macro(ident, def_id, item.id);
|
self.insert_unused_macro(ident, def_id, item.id, &rule_spans);
|
||||||
}
|
}
|
||||||
self.r.visibilities.insert(def_id, vis);
|
self.r.visibilities.insert(def_id, vis);
|
||||||
let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding(
|
let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding(
|
||||||
|
@ -1287,7 +1297,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
||||||
_ => self.resolve_visibility(&item.vis),
|
_ => self.resolve_visibility(&item.vis),
|
||||||
};
|
};
|
||||||
if vis != ty::Visibility::Public {
|
if vis != ty::Visibility::Public {
|
||||||
self.insert_unused_macro(ident, def_id, item.id);
|
self.insert_unused_macro(ident, def_id, item.id, &rule_spans);
|
||||||
}
|
}
|
||||||
self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
|
self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
|
||||||
self.r.visibilities.insert(def_id, vis);
|
self.r.visibilities.insert(def_id, vis);
|
||||||
|
|
|
@ -35,6 +35,9 @@ use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, Vis
|
||||||
use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet};
|
use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet};
|
||||||
use crate::{Segment, UseError};
|
use crate::{Segment, UseError};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
type Res = def::Res<ast::NodeId>;
|
type Res = def::Res<ast::NodeId>;
|
||||||
|
|
||||||
/// A vector of spans and replacements, a message and applicability.
|
/// A vector of spans and replacements, a message and applicability.
|
||||||
|
@ -2675,3 +2678,14 @@ fn is_span_suitable_for_use_injection(s: Span) -> bool {
|
||||||
// import or other generated ones
|
// import or other generated ones
|
||||||
!s.from_expansion()
|
!s.from_expansion()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert the given number into the corresponding ordinal
|
||||||
|
crate fn ordinalize(v: usize) -> String {
|
||||||
|
let suffix = match ((11..=13).contains(&(v % 100)), v % 10) {
|
||||||
|
(false, 1) => "st",
|
||||||
|
(false, 2) => "nd",
|
||||||
|
(false, 3) => "rd",
|
||||||
|
_ => "th",
|
||||||
|
};
|
||||||
|
format!("{v}{suffix}")
|
||||||
|
}
|
||||||
|
|
40
compiler/rustc_resolve/src/diagnostics/tests.rs
Normal file
40
compiler/rustc_resolve/src/diagnostics/tests.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
use super::ordinalize;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ordinalize() {
|
||||||
|
assert_eq!(ordinalize(1), "1st");
|
||||||
|
assert_eq!(ordinalize(2), "2nd");
|
||||||
|
assert_eq!(ordinalize(3), "3rd");
|
||||||
|
assert_eq!(ordinalize(4), "4th");
|
||||||
|
assert_eq!(ordinalize(5), "5th");
|
||||||
|
// ...
|
||||||
|
assert_eq!(ordinalize(10), "10th");
|
||||||
|
assert_eq!(ordinalize(11), "11th");
|
||||||
|
assert_eq!(ordinalize(12), "12th");
|
||||||
|
assert_eq!(ordinalize(13), "13th");
|
||||||
|
assert_eq!(ordinalize(14), "14th");
|
||||||
|
// ...
|
||||||
|
assert_eq!(ordinalize(20), "20th");
|
||||||
|
assert_eq!(ordinalize(21), "21st");
|
||||||
|
assert_eq!(ordinalize(22), "22nd");
|
||||||
|
assert_eq!(ordinalize(23), "23rd");
|
||||||
|
assert_eq!(ordinalize(24), "24th");
|
||||||
|
// ...
|
||||||
|
assert_eq!(ordinalize(30), "30th");
|
||||||
|
assert_eq!(ordinalize(31), "31st");
|
||||||
|
assert_eq!(ordinalize(32), "32nd");
|
||||||
|
assert_eq!(ordinalize(33), "33rd");
|
||||||
|
assert_eq!(ordinalize(34), "34th");
|
||||||
|
// ...
|
||||||
|
assert_eq!(ordinalize(7010), "7010th");
|
||||||
|
assert_eq!(ordinalize(7011), "7011th");
|
||||||
|
assert_eq!(ordinalize(7012), "7012th");
|
||||||
|
assert_eq!(ordinalize(7013), "7013th");
|
||||||
|
assert_eq!(ordinalize(7014), "7014th");
|
||||||
|
// ...
|
||||||
|
assert_eq!(ordinalize(7020), "7020th");
|
||||||
|
assert_eq!(ordinalize(7021), "7021st");
|
||||||
|
assert_eq!(ordinalize(7022), "7022nd");
|
||||||
|
assert_eq!(ordinalize(7023), "7023rd");
|
||||||
|
assert_eq!(ordinalize(7024), "7024th");
|
||||||
|
}
|
|
@ -975,6 +975,7 @@ pub struct Resolver<'a> {
|
||||||
local_macro_def_scopes: FxHashMap<LocalDefId, Module<'a>>,
|
local_macro_def_scopes: FxHashMap<LocalDefId, Module<'a>>,
|
||||||
ast_transform_scopes: FxHashMap<LocalExpnId, Module<'a>>,
|
ast_transform_scopes: FxHashMap<LocalExpnId, Module<'a>>,
|
||||||
unused_macros: FxHashMap<LocalDefId, (NodeId, Ident)>,
|
unused_macros: FxHashMap<LocalDefId, (NodeId, Ident)>,
|
||||||
|
unused_macro_rules: FxHashMap<(LocalDefId, usize), (Ident, Span)>,
|
||||||
proc_macro_stubs: FxHashSet<LocalDefId>,
|
proc_macro_stubs: FxHashSet<LocalDefId>,
|
||||||
/// Traces collected during macro resolution and validated when it's complete.
|
/// Traces collected during macro resolution and validated when it's complete.
|
||||||
single_segment_macro_resolutions:
|
single_segment_macro_resolutions:
|
||||||
|
@ -1374,6 +1375,7 @@ impl<'a> Resolver<'a> {
|
||||||
potentially_unused_imports: Vec::new(),
|
potentially_unused_imports: Vec::new(),
|
||||||
struct_constructors: Default::default(),
|
struct_constructors: Default::default(),
|
||||||
unused_macros: Default::default(),
|
unused_macros: Default::default(),
|
||||||
|
unused_macro_rules: Default::default(),
|
||||||
proc_macro_stubs: Default::default(),
|
proc_macro_stubs: Default::default(),
|
||||||
single_segment_macro_resolutions: Default::default(),
|
single_segment_macro_resolutions: Default::default(),
|
||||||
multi_segment_macro_resolutions: Default::default(),
|
multi_segment_macro_resolutions: Default::default(),
|
||||||
|
|
|
@ -22,7 +22,8 @@ use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
|
||||||
use rustc_hir::def_id::{CrateNum, LocalDefId};
|
use rustc_hir::def_id::{CrateNum, LocalDefId};
|
||||||
use rustc_middle::middle::stability;
|
use rustc_middle::middle::stability;
|
||||||
use rustc_middle::ty::RegisteredTools;
|
use rustc_middle::ty::RegisteredTools;
|
||||||
use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNUSED_MACROS};
|
use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE};
|
||||||
|
use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
|
||||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
|
@ -311,6 +312,11 @@ impl<'a> ResolverExpand for Resolver<'a> {
|
||||||
Ok(ext)
|
Ok(ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn record_macro_rule_usage(&mut self, id: NodeId, rule_i: usize) {
|
||||||
|
let did = self.local_def_id(id);
|
||||||
|
self.unused_macro_rules.remove(&(did, rule_i));
|
||||||
|
}
|
||||||
|
|
||||||
fn check_unused_macros(&mut self) {
|
fn check_unused_macros(&mut self) {
|
||||||
for (_, &(node_id, ident)) in self.unused_macros.iter() {
|
for (_, &(node_id, ident)) in self.unused_macros.iter() {
|
||||||
self.lint_buffer.buffer_lint(
|
self.lint_buffer.buffer_lint(
|
||||||
|
@ -320,6 +326,23 @@ impl<'a> ResolverExpand for Resolver<'a> {
|
||||||
&format!("unused macro definition: `{}`", ident.as_str()),
|
&format!("unused macro definition: `{}`", ident.as_str()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
for (&(def_id, arm_i), &(ident, rule_span)) in self.unused_macro_rules.iter() {
|
||||||
|
if self.unused_macros.contains_key(&def_id) {
|
||||||
|
// We already lint the entire macro as unused
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let node_id = self.def_id_to_node_id[def_id];
|
||||||
|
self.lint_buffer.buffer_lint(
|
||||||
|
UNUSED_MACRO_RULES,
|
||||||
|
node_id,
|
||||||
|
rule_span,
|
||||||
|
&format!(
|
||||||
|
"{} rule of macro `{}` is never used",
|
||||||
|
crate::diagnostics::ordinalize(arm_i + 1),
|
||||||
|
ident.as_str()
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool {
|
fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool {
|
||||||
|
@ -830,10 +853,15 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile the macro into a `SyntaxExtension` and possibly replace
|
/// Compile the macro into a `SyntaxExtension` and its rule spans.
|
||||||
/// its expander to a pre-defined one for built-in macros.
|
///
|
||||||
crate fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> SyntaxExtension {
|
/// Possibly replace its expander to a pre-defined one for built-in macros.
|
||||||
let mut result = compile_declarative_macro(
|
crate fn compile_macro(
|
||||||
|
&mut self,
|
||||||
|
item: &ast::Item,
|
||||||
|
edition: Edition,
|
||||||
|
) -> (SyntaxExtension, Vec<Span>) {
|
||||||
|
let (mut result, mut rule_spans) = compile_declarative_macro(
|
||||||
&self.session,
|
&self.session,
|
||||||
self.session.features_untracked(),
|
self.session.features_untracked(),
|
||||||
item,
|
item,
|
||||||
|
@ -849,6 +877,7 @@ impl<'a> Resolver<'a> {
|
||||||
match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) {
|
match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) {
|
||||||
BuiltinMacroState::NotYetSeen(ext) => {
|
BuiltinMacroState::NotYetSeen(ext) => {
|
||||||
result.kind = ext;
|
result.kind = ext;
|
||||||
|
rule_spans = Vec::new();
|
||||||
if item.id != ast::DUMMY_NODE_ID {
|
if item.id != ast::DUMMY_NODE_ID {
|
||||||
self.builtin_macro_kinds
|
self.builtin_macro_kinds
|
||||||
.insert(self.local_def_id(item.id), result.macro_kind());
|
.insert(self.local_def_id(item.id), result.macro_kind());
|
||||||
|
@ -871,6 +900,6 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
(result, rule_spans)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ macro_rules! vec {
|
||||||
// `slice::into_vec` function which is only available with cfg(test)
|
// `slice::into_vec` function which is only available with cfg(test)
|
||||||
// NB see the slice::hack module in slice.rs for more information
|
// NB see the slice::hack module in slice.rs for more information
|
||||||
#[cfg(all(not(no_global_oom_handling), test))]
|
#[cfg(all(not(no_global_oom_handling), test))]
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_macro_rules))]
|
||||||
macro_rules! vec {
|
macro_rules! vec {
|
||||||
() => (
|
() => (
|
||||||
$crate::vec::Vec::new()
|
$crate::vec::Vec::new()
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit d215afe9d1cf79c5edb0dfd3cdf4c50aca1f1760
|
Subproject commit 28335054b1f417175ab5005cf1d9cf7937737930
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#![feature(const_float_bits_conv)]
|
#![feature(const_float_bits_conv)]
|
||||||
#![feature(const_float_classify)]
|
#![feature(const_float_classify)]
|
||||||
|
#![allow(unused_macro_rules)]
|
||||||
|
|
||||||
// Don't promote
|
// Don't promote
|
||||||
const fn nop<T>(x: T) -> T { x }
|
const fn nop<T>(x: T) -> T { x }
|
||||||
|
|
49
src/test/ui/lint/unused/unused-macro-rules-decl.rs
Normal file
49
src/test/ui/lint/unused/unused-macro-rules-decl.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#![feature(decl_macro)]
|
||||||
|
#![deny(unused_macro_rules)]
|
||||||
|
// To make sure we are not hitting this
|
||||||
|
#![deny(unused_macros)]
|
||||||
|
|
||||||
|
// Most simple case
|
||||||
|
macro num {
|
||||||
|
(one) => { 1 },
|
||||||
|
(two) => { 2 }, //~ ERROR: 2nd rule of macro
|
||||||
|
(three) => { 3 },
|
||||||
|
(four) => { 4 }, //~ ERROR: 4th rule of macro
|
||||||
|
}
|
||||||
|
const _NUM: u8 = num!(one) + num!(three);
|
||||||
|
|
||||||
|
// Check that allowing the lint works
|
||||||
|
#[allow(unused_macro_rules)]
|
||||||
|
macro num_allowed {
|
||||||
|
(one) => { 1 },
|
||||||
|
(two) => { 2 },
|
||||||
|
(three) => { 3 },
|
||||||
|
(four) => { 4 },
|
||||||
|
}
|
||||||
|
const _NUM_ALLOWED: u8 = num_allowed!(one) + num_allowed!(three);
|
||||||
|
|
||||||
|
// Check that macro calls inside the macro trigger as usage
|
||||||
|
macro num_rec {
|
||||||
|
(one) => { 1 },
|
||||||
|
(two) => {
|
||||||
|
num_rec!(one) + num_rec!(one)
|
||||||
|
},
|
||||||
|
(three) => { //~ ERROR: 3rd rule of macro
|
||||||
|
num_rec!(one) + num_rec!(two)
|
||||||
|
},
|
||||||
|
(four) => {
|
||||||
|
num_rec!(two) + num_rec!(two)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const _NUM_RECURSIVE: u8 = num_rec!(four);
|
||||||
|
|
||||||
|
// No error if the macro is public
|
||||||
|
pub macro num_public {
|
||||||
|
(one) => { 1 },
|
||||||
|
(two) => { 2 },
|
||||||
|
(three) => { 3 },
|
||||||
|
(four) => { 4 },
|
||||||
|
}
|
||||||
|
const _NUM_PUBLIC: u8 = num_public!(one) + num_public!(three);
|
||||||
|
|
||||||
|
fn main() {}
|
26
src/test/ui/lint/unused/unused-macro-rules-decl.stderr
Normal file
26
src/test/ui/lint/unused/unused-macro-rules-decl.stderr
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
error: 4th rule of macro `num` is never used
|
||||||
|
--> $DIR/unused-macro-rules-decl.rs:11:5
|
||||||
|
|
|
||||||
|
LL | (four) => { 4 },
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/unused-macro-rules-decl.rs:2:9
|
||||||
|
|
|
||||||
|
LL | #![deny(unused_macro_rules)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: 2nd rule of macro `num` is never used
|
||||||
|
--> $DIR/unused-macro-rules-decl.rs:9:5
|
||||||
|
|
|
||||||
|
LL | (two) => { 2 },
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: 3rd rule of macro `num_rec` is never used
|
||||||
|
--> $DIR/unused-macro-rules-decl.rs:31:5
|
||||||
|
|
|
||||||
|
LL | (three) => {
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
|
@ -1,29 +1,47 @@
|
||||||
|
#![deny(unused_macro_rules)]
|
||||||
|
// To make sure we are not hitting this
|
||||||
#![deny(unused_macros)]
|
#![deny(unused_macros)]
|
||||||
|
|
||||||
// Most simple case
|
// Most simple case
|
||||||
macro_rules! unused { //~ ERROR: unused macro definition
|
macro_rules! num {
|
||||||
() => {};
|
(one) => { 1 };
|
||||||
|
(two) => { 2 }; //~ ERROR: 2nd rule of macro
|
||||||
|
(three) => { 3 };
|
||||||
|
(four) => { 4 }; //~ ERROR: 4th rule of macro
|
||||||
}
|
}
|
||||||
|
const _NUM: u8 = num!(one) + num!(three);
|
||||||
|
|
||||||
// Test macros created by macros
|
// Check that allowing the lint works
|
||||||
macro_rules! create_macro {
|
#[allow(unused_macro_rules)]
|
||||||
() => {
|
macro_rules! num_allowed {
|
||||||
macro_rules! m { //~ ERROR: unused macro definition
|
(one) => { 1 };
|
||||||
() => {};
|
(two) => { 2 };
|
||||||
}
|
(three) => { 3 };
|
||||||
|
(four) => { 4 };
|
||||||
|
}
|
||||||
|
const _NUM_ALLOWED: u8 = num_allowed!(one) + num_allowed!(three);
|
||||||
|
|
||||||
|
// Check that macro calls inside the macro trigger as usage
|
||||||
|
macro_rules! num_rec {
|
||||||
|
(one) => { 1 };
|
||||||
|
(two) => {
|
||||||
|
num_rec!(one) + num_rec!(one)
|
||||||
};
|
};
|
||||||
|
(three) => { //~ ERROR: 3rd rule of macro
|
||||||
|
num_rec!(one) + num_rec!(two)
|
||||||
|
};
|
||||||
|
(four) => { num_rec!(two) + num_rec!(two) };
|
||||||
}
|
}
|
||||||
create_macro!();
|
const _NUM_RECURSIVE: u8 = num_rec!(four);
|
||||||
|
|
||||||
#[allow(unused_macros)]
|
// No error if the macro is being exported
|
||||||
mod bar {
|
#[macro_export]
|
||||||
// Test that putting the #[deny] close to the macro's definition
|
macro_rules! num_exported {
|
||||||
// works.
|
(one) => { 1 };
|
||||||
|
(two) => { 2 };
|
||||||
#[deny(unused_macros)]
|
(three) => { 3 };
|
||||||
macro_rules! unused { //~ ERROR: unused macro definition
|
(four) => { 4 };
|
||||||
() => {};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
const _NUM_EXPORTED: u8 = num_exported!(one) + num_exported!(three);
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,32 +1,26 @@
|
||||||
error: unused macro definition: `unused`
|
error: 4th rule of macro `num` is never used
|
||||||
--> $DIR/unused-macro-rules.rs:4:14
|
--> $DIR/unused-macro-rules.rs:10:5
|
||||||
|
|
|
|
||||||
LL | macro_rules! unused {
|
LL | (four) => { 4 };
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/unused-macro-rules.rs:1:9
|
--> $DIR/unused-macro-rules.rs:1:9
|
||||||
|
|
|
|
||||||
LL | #![deny(unused_macros)]
|
LL | #![deny(unused_macro_rules)]
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: unused macro definition: `m`
|
error: 2nd rule of macro `num` is never used
|
||||||
--> $DIR/unused-macro-rules.rs:11:22
|
--> $DIR/unused-macro-rules.rs:8:5
|
||||||
|
|
|
|
||||||
LL | macro_rules! m {
|
LL | (two) => { 2 };
|
||||||
| ^
|
| ^^^^^
|
||||||
|
|
||||||
error: unused macro definition: `unused`
|
error: 3rd rule of macro `num_rec` is never used
|
||||||
--> $DIR/unused-macro-rules.rs:24:18
|
--> $DIR/unused-macro-rules.rs:30:5
|
||||||
|
|
|
|
||||||
LL | macro_rules! unused {
|
LL | (three) => {
|
||||||
| ^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
||||||
note: the lint level is defined here
|
|
||||||
--> $DIR/unused-macro-rules.rs:23:12
|
|
||||||
|
|
|
||||||
LL | #[deny(unused_macros)]
|
|
||||||
| ^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
#![deny(unused_macros)]
|
#![deny(unused_macros)]
|
||||||
|
// To make sure we are not hitting this
|
||||||
|
#![deny(unused_macro_rules)]
|
||||||
|
|
||||||
// Most simple case
|
// Most simple case
|
||||||
macro unused { //~ ERROR: unused macro definition
|
macro unused { //~ ERROR: unused macro definition
|
|
@ -1,29 +1,29 @@
|
||||||
error: unused macro definition: `unused`
|
error: unused macro definition: `unused`
|
||||||
--> $DIR/unused-macro.rs:5:7
|
--> $DIR/unused-macros-decl.rs:7:7
|
||||||
|
|
|
|
||||||
LL | macro unused {
|
LL | macro unused {
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/unused-macro.rs:2:9
|
--> $DIR/unused-macros-decl.rs:2:9
|
||||||
|
|
|
|
||||||
LL | #![deny(unused_macros)]
|
LL | #![deny(unused_macros)]
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: unused macro definition: `unused`
|
error: unused macro definition: `unused`
|
||||||
--> $DIR/unused-macro.rs:15:11
|
--> $DIR/unused-macros-decl.rs:17:11
|
||||||
|
|
|
|
||||||
LL | macro unused {
|
LL | macro unused {
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/unused-macro.rs:14:12
|
--> $DIR/unused-macros-decl.rs:16:12
|
||||||
|
|
|
|
||||||
LL | #[deny(unused_macros)]
|
LL | #[deny(unused_macros)]
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: unused macro definition: `unused`
|
error: unused macro definition: `unused`
|
||||||
--> $DIR/unused-macro.rs:21:22
|
--> $DIR/unused-macros-decl.rs:23:22
|
||||||
|
|
|
|
||||||
LL | pub(crate) macro unused {
|
LL | pub(crate) macro unused {
|
||||||
| ^^^^^^
|
| ^^^^^^
|
31
src/test/ui/lint/unused/unused-macros.rs
Normal file
31
src/test/ui/lint/unused/unused-macros.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#![deny(unused_macros)]
|
||||||
|
// To make sure we are not hitting this
|
||||||
|
#![deny(unused_macro_rules)]
|
||||||
|
|
||||||
|
// 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() {}
|
32
src/test/ui/lint/unused/unused-macros.stderr
Normal file
32
src/test/ui/lint/unused/unused-macros.stderr
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
error: unused macro definition: `unused`
|
||||||
|
--> $DIR/unused-macros.rs:6:14
|
||||||
|
|
|
||||||
|
LL | macro_rules! unused {
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/unused-macros.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(unused_macros)]
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: unused macro definition: `m`
|
||||||
|
--> $DIR/unused-macros.rs:13:22
|
||||||
|
|
|
||||||
|
LL | macro_rules! m {
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: unused macro definition: `unused`
|
||||||
|
--> $DIR/unused-macros.rs:26:18
|
||||||
|
|
|
||||||
|
LL | macro_rules! unused {
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/unused-macros.rs:25:12
|
||||||
|
|
|
||||||
|
LL | #[deny(unused_macros)]
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
// run-pass
|
// run-pass
|
||||||
|
#![allow(unused_macro_rules)]
|
||||||
|
|
||||||
/// A compile-time map from identifiers to arbitrary (heterogeneous) expressions
|
/// A compile-time map from identifiers to arbitrary (heterogeneous) expressions
|
||||||
macro_rules! ident_map {
|
macro_rules! ident_map {
|
||||||
( $name:ident = { $($key:ident => $e:expr,)* } ) => {
|
( $name:ident = { $($key:ident => $e:expr,)* } ) => {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// run-pass
|
// run-pass
|
||||||
|
|
||||||
|
#[allow(unused_macro_rules)]
|
||||||
macro_rules! a {
|
macro_rules! a {
|
||||||
($i:literal) => { "right" };
|
($i:literal) => { "right" };
|
||||||
($i:tt) => { "wrong" };
|
($i:tt) => { "wrong" };
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// run-pass
|
// run-pass
|
||||||
|
#![allow(unused_macro_rules)]
|
||||||
|
|
||||||
//{{{ issue 40569 ==============================================================
|
//{{{ issue 40569 ==============================================================
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ macro_rules! only_expr {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_macro_rules)]
|
||||||
macro_rules! mtester_dbg {
|
macro_rules! mtester_dbg {
|
||||||
($l:literal) => {
|
($l:literal) => {
|
||||||
&format!("macro caught literal: {:?}", $l)
|
&format!("macro caught literal: {:?}", $l)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// run-pass
|
// run-pass
|
||||||
#![allow(dead_code, unused_imports)]
|
#![allow(dead_code, unused_imports, unused_macro_rules)]
|
||||||
#![feature(crate_visibility_modifier)]
|
#![feature(crate_visibility_modifier)]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
// run-pass
|
// run-pass
|
||||||
|
#![allow(unused_macro_rules)]
|
||||||
|
|
||||||
macro_rules! m {
|
macro_rules! m {
|
||||||
($e:expr) => {
|
($e:expr) => {
|
||||||
"expr includes attr"
|
"expr includes attr"
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
// run-pass
|
// run-pass
|
||||||
|
#![allow(unused_macro_rules)]
|
||||||
|
|
||||||
use std::ops::*;
|
use std::ops::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// Test that failing macro matchers will not cause pre-expansion errors
|
// Test that failing macro matchers will not cause pre-expansion errors
|
||||||
// even though they use a feature that is pre-expansion gated.
|
// even though they use a feature that is pre-expansion gated.
|
||||||
|
|
||||||
|
#[allow(unused_macro_rules)]
|
||||||
macro_rules! m {
|
macro_rules! m {
|
||||||
($e:expr) => { 0 }; // This fails on the input below due to `, foo`.
|
($e:expr) => { 0 }; // This fails on the input below due to `, foo`.
|
||||||
($e:expr,) => { 1 }; // This also fails to match due to `foo`.
|
($e:expr,) => { 1 }; // This also fails to match due to `foo`.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![allow(dead_code, unused_variables, non_camel_case_types, non_upper_case_globals)]
|
#![allow(dead_code, unused_variables, unused_macro_rules, bad_style)]
|
||||||
#![deny(keyword_idents)]
|
#![deny(keyword_idents)]
|
||||||
|
|
||||||
// edition:2015
|
// edition:2015
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![allow(dead_code, unused_variables, non_camel_case_types, non_upper_case_globals)]
|
#![allow(dead_code, unused_variables, unused_macro_rules, bad_style)]
|
||||||
#![deny(keyword_idents)]
|
#![deny(keyword_idents)]
|
||||||
|
|
||||||
// edition:2015
|
// edition:2015
|
||||||
|
|
|
@ -280,10 +280,6 @@ fn main() {
|
||||||
fn register_all() -> Vec<(&'static str, Option<&'static str>)> {
|
fn register_all() -> Vec<(&'static str, Option<&'static str>)> {
|
||||||
let mut long_codes: Vec<(&'static str, Option<&'static str>)> = Vec::new();
|
let mut long_codes: Vec<(&'static str, Option<&'static str>)> = Vec::new();
|
||||||
macro_rules! register_diagnostics {
|
macro_rules! register_diagnostics {
|
||||||
($($ecode:ident: $message:expr,)*) => (
|
|
||||||
register_diagnostics!{$($ecode:$message,)* ;}
|
|
||||||
);
|
|
||||||
|
|
||||||
($($ecode:ident: $message:expr,)* ; $($code:ident,)*) => (
|
($($ecode:ident: $message:expr,)* ; $($code:ident,)*) => (
|
||||||
$(
|
$(
|
||||||
{long_codes.extend([
|
{long_codes.extend([
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue