about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/lint/internal.rs34
-rw-r--r--src/libsyntax_pos/symbol.rs3
-rw-r--r--src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs18
-rw-r--r--src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr13
4 files changed, 57 insertions, 11 deletions
diff --git a/src/librustc/lint/internal.rs b/src/librustc/lint/internal.rs
index d3996c4e37a..9763801f0d9 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 756bc8c29d8..4b8535fa625 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 92f8e8364a7..89fa838768e 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 9ddd6af472a..a033b0a07e0 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