diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 868555a72b0d1..5dc0631cf7578 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -3173,3 +3173,81 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { } } } + +declare_lint! { + /// The `special_module_name` lint detects module + /// declarations for files that have a special meaning. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// mod lib; + /// + /// fn main() { + /// lib::run(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Cargo recognizes `lib.rs` and `main.rs` as the root of a + /// library or binary crate, so declaring them as modules + /// will lead to miscompilation of the crate unless configured + /// explicitly. + /// + /// To access a library from a binary target within the same crate, + /// use `your_crate_name::` as the path path instead of `lib::`: + /// + /// ```rust,compile_fail + /// // bar/src/lib.rs + /// fn run() { + /// // ... + /// } + /// + /// // bar/src/main.rs + /// fn main() { + /// bar::run(); + /// } + /// ``` + /// + /// Binary targets cannot be used as libraries and so declaring + /// one as a module is not allowed. + pub SPECIAL_MODULE_NAME, + Warn, + "module declarations for files with a special meaning", +} + +declare_lint_pass!(SpecialModuleName => [SPECIAL_MODULE_NAME]); + +impl EarlyLintPass for SpecialModuleName { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) { + for item in &krate.items { + if let ast::ItemKind::Mod( + _, + ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _), + ) = item.kind + { + if item.attrs.iter().any(|a| a.has_name(sym::path)) { + continue; + } + + match item.ident.name.as_str() { + "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| { + lint.build("found module declaration for lib.rs") + .note("lib.rs is the root of this crate's library target") + .help("to refer to it from other targets, use the library's name as the path") + .emit() + }), + "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| { + lint.build("found module declaration for main.rs") + .note("a binary crate cannot be used as library") + .emit() + }), + _ => continue + } + } + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c3065e4a2d938..4decbc5f3f6d0 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -131,6 +131,7 @@ macro_rules! early_lint_passes { UnusedBraces: UnusedBraces, UnusedImportBraces: UnusedImportBraces, UnsafeCode: UnsafeCode, + SpecialModuleName: SpecialModuleName, AnonymousParameters: AnonymousParameters, EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), NonCamelCaseTypes: NonCamelCaseTypes, diff --git a/src/test/ui/modules/auxiliary/dummy_lib.rs b/src/test/ui/modules/auxiliary/dummy_lib.rs new file mode 100644 index 0000000000000..ef805c1f02031 --- /dev/null +++ b/src/test/ui/modules/auxiliary/dummy_lib.rs @@ -0,0 +1,2 @@ +#[allow(dead_code)] +pub struct Dummy; diff --git a/src/test/ui/modules/special_module_name.rs b/src/test/ui/modules/special_module_name.rs new file mode 100644 index 0000000000000..15c59b2da828c --- /dev/null +++ b/src/test/ui/modules/special_module_name.rs @@ -0,0 +1,8 @@ +mod lib; +//~^ WARN found module declaration for lib.rs +//~| ERROR file not found for module `lib` +mod main; +//~^ WARN found module declaration for main.rs +//~| ERROR file not found for module `main` + +fn main() {} diff --git a/src/test/ui/modules/special_module_name.stderr b/src/test/ui/modules/special_module_name.stderr new file mode 100644 index 0000000000000..8b3da29386df2 --- /dev/null +++ b/src/test/ui/modules/special_module_name.stderr @@ -0,0 +1,37 @@ +error[E0583]: file not found for module `lib` + --> $DIR/special_module_name.rs:1:1 + | +LL | mod lib; + | ^^^^^^^^ + | + = help: to create the module `lib`, create file "$DIR/lib.rs" or "$DIR/lib/mod.rs" + +error[E0583]: file not found for module `main` + --> $DIR/special_module_name.rs:4:1 + | +LL | mod main; + | ^^^^^^^^^ + | + = help: to create the module `main`, create file "$DIR/main.rs" or "$DIR/main/mod.rs" + +warning: found module declaration for lib.rs + --> $DIR/special_module_name.rs:1:1 + | +LL | mod lib; + | ^^^^^^^^ + | + = note: `#[warn(special_module_name)]` on by default + = note: lib.rs is the root of this crate's library target + = help: to refer to it from other targets, use the library's name as the path + +warning: found module declaration for main.rs + --> $DIR/special_module_name.rs:4:1 + | +LL | mod main; + | ^^^^^^^^^ + | + = note: a binary crate cannot be used as library + +error: aborting due to 2 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0583`. diff --git a/src/test/ui/modules/special_module_name_ignore.rs b/src/test/ui/modules/special_module_name_ignore.rs new file mode 100644 index 0000000000000..07cea9b2b05a1 --- /dev/null +++ b/src/test/ui/modules/special_module_name_ignore.rs @@ -0,0 +1,9 @@ +// run-pass + +#[path = "auxiliary/dummy_lib.rs"] +mod lib; + +#[path = "auxiliary/dummy_lib.rs"] +mod main; + +fn main() {}