diff --git a/src/librustc/lint/internal.rs b/src/librustc/lint/internal.rs index d3996c4e37a9..9763801f0d9a 100644 --- a/src/librustc/lint/internal.rs +++ b/src/librustc/lint/internal.rs @@ -9,6 +9,7 @@ use errors::Applicability; use rustc_data_structures::fx::FxHashMap; use syntax::ast::{Ident, Item, ItemKind}; use syntax::symbol::{sym, Symbol}; +use syntax_pos::ExpnInfo; declare_lint! { pub DEFAULT_HASH_TYPES, @@ -225,19 +226,32 @@ declare_lint_pass!(LintPassImpl => [LINT_PASS_IMPL_WITHOUT_MACRO]); impl EarlyLintPass for LintPassImpl { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { if let ItemKind::Impl(_, _, _, _, Some(lint_pass), _, _) = &item.node { - if !lint_pass.path.span.ctxt().outer_expn_info().is_some() { - if let Some(last) = lint_pass.path.segments.last() { - if last.ident.as_str() == "LintPass" { - cx.struct_span_lint( - LINT_PASS_IMPL_WITHOUT_MACRO, - lint_pass.path.span, - "implementing `LintPass` by hand", - ) - .help("try using `declare_lint_pass!` or `impl_lint_pass!` instead") - .emit(); + if let Some(last) = lint_pass.path.segments.last() { + if last.ident.name == sym::LintPass { + match &lint_pass.path.span.ctxt().outer_expn_info() { + Some(info) if is_lint_pass_expansion(info) => {} + _ => { + cx.struct_span_lint( + LINT_PASS_IMPL_WITHOUT_MACRO, + lint_pass.path.span, + "implementing `LintPass` by hand", + ) + .help("try using `declare_lint_pass!` or `impl_lint_pass!` instead") + .emit(); + } } } } } } } + +fn is_lint_pass_expansion(expn_info: &ExpnInfo) -> bool { + if expn_info.format.name() == sym::impl_lint_pass { + true + } else if let Some(info) = expn_info.call_site.ctxt().outer_expn_info() { + info.format.name() == sym::declare_lint_pass + } else { + false + } +} diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 756bc8c29d82..4b8535fa625b 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -214,6 +214,7 @@ symbols! { custom_inner_attributes, custom_test_frameworks, c_variadic, + declare_lint_pass, decl_macro, Default, default_lib_allocator, @@ -324,6 +325,7 @@ symbols! { if_while_or_patterns, ignore, impl_header_lifetime_elision, + impl_lint_pass, impl_trait_in_bindings, import_shadowing, index, @@ -365,6 +367,7 @@ symbols! { link_llvm_intrinsics, link_name, link_section, + LintPass, lint_reasons, literal, local_inner_macros, diff --git a/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs b/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs index 92f8e8364a77..89fa838768e8 100644 --- a/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs +++ b/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs @@ -26,6 +26,24 @@ impl LintPass for Foo { //~ERROR implementing `LintPass` by hand } } +macro_rules! custom_lint_pass_macro { + () => { + struct Custom; + + impl LintPass for Custom { //~ERROR implementing `LintPass` by hand + fn get_lints(&self) -> LintArray { + lint_array!(TEST_LINT) + } + + fn name(&self) -> &'static str { + "Custom" + } + } + }; +} + +custom_lint_pass_macro!(); + struct Bar; impl_lint_pass!(Bar => [TEST_LINT]); diff --git a/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr b/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr index 9ddd6af472a8..a033b0a07e00 100644 --- a/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr +++ b/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr @@ -11,5 +11,16 @@ LL | #![deny(lint_pass_impl_without_macro)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: try using `declare_lint_pass!` or `impl_lint_pass!` instead -error: aborting due to previous error +error: implementing `LintPass` by hand + --> $DIR/lint_pass_impl_without_macro.rs:33:14 + | +LL | impl LintPass for Custom { + | ^^^^^^^^ +... +LL | custom_lint_pass_macro!(); + | -------------------------- in this macro invocation + | + = help: try using `declare_lint_pass!` or `impl_lint_pass!` instead + +error: aborting due to 2 previous errors