From 56dd0c2827666b29ca57eed33fe4503787028f33 Mon Sep 17 00:00:00 2001 From: ravlyn Date: Sun, 5 Jul 2026 23:54:46 +0700 Subject: [PATCH] rustc_passes: lint unused `#[path]` attributes on inline modules --- .../rustc_attr_parsing/src/attributes/path.rs | 2 +- .../rustc_hir/src/attrs/data_structures.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 55 ++++++++++++++++++- compiler/rustc_passes/src/diagnostics.rs | 2 + tests/ui/attributes/auxiliary/foo.rs | 1 + tests/ui/attributes/path-inline-module.rs | 35 ++++++++++++ tests/ui/attributes/path-inline-module.stderr | 27 +++++++++ 7 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 tests/ui/attributes/auxiliary/foo.rs create mode 100644 tests/ui/attributes/path-inline-module.rs create mode 100644 tests/ui/attributes/path-inline-module.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/path.rs b/compiler/rustc_attr_parsing/src/attributes/path.rs index ad4641c4be7f2..12e2deafdba27 100644 --- a/compiler/rustc_attr_parsing/src/attributes/path.rs +++ b/compiler/rustc_attr_parsing/src/attributes/path.rs @@ -19,6 +19,6 @@ impl SingleAttributeParser for PathParser { let nv = cx.expect_name_value(args, cx.attr_span, None)?; let path = cx.expect_string_literal(nv)?; - Some(AttributeKind::Path(path)) + Some(AttributeKind::Path(path, cx.attr_span, cx.attr_style)) } } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 17d00863d99d5..eb45b1fc33efb 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1277,7 +1277,7 @@ pub enum AttributeKind { }, /// Represents `#[path]` - Path(Symbol), + Path(Symbol, Span, AttrStyle), /// Represents `#[pattern_complexity_limit]` PatternComplexityLimit { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7ae6005e9bc98..fa884f5599271 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -299,7 +299,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Optimize(..) => (), AttributeKind::PanicRuntime => (), AttributeKind::PatchableFunctionEntry { .. } => (), - AttributeKind::Path(..) => (), + AttributeKind::Path(_, span, style) => self.check_path(*span, style, hir_id), AttributeKind::PatternComplexityLimit { .. } => (), AttributeKind::PinV2(..) => (), AttributeKind::PreludeImport => (), @@ -416,6 +416,59 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + fn check_path(&self, span: Span, attr_style: &AttrStyle, hir_id: HirId) { + if matches!(attr_style, AttrStyle::Inner) { + return; + } + + let Node::Item(item) = self.tcx.hir_node(hir_id) else { + return; + }; + + let ItemKind::Mod(_, module) = &item.kind else { + return; + }; + + if !item.span.contains(module.spans.inner_span) { + return; + } + + let has_out_of_line_child_module = module.item_ids.iter().any(|item_id| { + let child = self.tcx.hir_item(*item_id); + + let ItemKind::Mod(_, child_mod) = &child.kind else { + return false; + }; + + !child.span.contains(child_mod.spans.inner_span) + }); + + if has_out_of_line_child_module { + return; + } + + let has_child_module_with_path_attr = module.item_ids.iter().any(|item_id| { + let child = self.tcx.hir_item(*item_id); + + matches!(child.kind, ItemKind::Mod(..)) + && find_attr!(self.tcx, child.hir_id(), Path(..)) + }); + + if has_child_module_with_path_attr { + return; + } + + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + span, + diagnostics::Unused { + attr_span: span, + note: diagnostics::UnusedNote::PathOnInlineModule, + }, + ); + } + fn check_rustc_must_implement_one_of( &self, attr_span: Span, diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index 92562cc462b87..95c6c4a5d478c 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -281,6 +281,8 @@ pub(crate) enum UnusedNote { LinkerMessagesBinaryCrateOnly, #[note("the `dead_code_pub_in_binary` lint has no effect in library crates")] NoEffectDeadCodePubInBinary, + #[note("`#[path]` is unused on this inline module")] + PathOnInlineModule, } #[derive(Diagnostic)] diff --git a/tests/ui/attributes/auxiliary/foo.rs b/tests/ui/attributes/auxiliary/foo.rs new file mode 100644 index 0000000000000..e5736aedfdc7c --- /dev/null +++ b/tests/ui/attributes/auxiliary/foo.rs @@ -0,0 +1 @@ +mod foo {} diff --git a/tests/ui/attributes/path-inline-module.rs b/tests/ui/attributes/path-inline-module.rs new file mode 100644 index 0000000000000..d5420d62a309b --- /dev/null +++ b/tests/ui/attributes/path-inline-module.rs @@ -0,0 +1,35 @@ +//@ check-pass + +fn main() {} + +#[path = "foo.rs"] //~ WARN unused attribute [unused_attributes] +mod inline_module {} + +#[path = "auxiliary/foo.rs"] +mod outline_module; // Should not warn + +mod inline_with_inner_path { + #![path = "auxiliary"] + + #[path = "foo.rs"] // Should not warn + mod file_submodule; +} + +mod inline_with_inline_child { + #![path = "auxiliary"] + + #[path = "foo.rs"] //~ WARN unused attribute [unused_attributes] + mod nested_inline_module {} +} + +#[path = "auxiliary"] +mod inline_parent_with_file_child { + #[path = "foo.rs"] // Should not warn + mod file_submodule; +} + +#[path = "auxiliary"] +mod inline_parent_with_inline_child { + #[path = "foo.rs"] //~ WARN unused attribute [unused_attributes] + mod inline_submodule {} +} diff --git a/tests/ui/attributes/path-inline-module.stderr b/tests/ui/attributes/path-inline-module.stderr new file mode 100644 index 0000000000000..25ec02d08af6e --- /dev/null +++ b/tests/ui/attributes/path-inline-module.stderr @@ -0,0 +1,27 @@ +warning: unused attribute + --> $DIR/path-inline-module.rs:5:1 + | +LL | #[path = "foo.rs"] + | ^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[path]` is unused on this inline module + = note: requested on the command line with `-W unused-attributes` + +warning: unused attribute + --> $DIR/path-inline-module.rs:21:5 + | +LL | #[path = "foo.rs"] + | ^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[path]` is unused on this inline module + +warning: unused attribute + --> $DIR/path-inline-module.rs:33:5 + | +LL | #[path = "foo.rs"] + | ^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: `#[path]` is unused on this inline module + +warning: 3 warnings emitted +