From 65f862a677dbab7ba113e83c792a33c4abfbd798 Mon Sep 17 00:00:00 2001 From: ShigrafS Date: Sat, 31 Jan 2026 19:31:56 +0530 Subject: [PATCH 1/4] feat(lints): implement pr_missing_newline lint and fix build --- .cargo/config.toml | 2 +- Cargo.lock | 23 +++++++++++ Cargo.toml | 2 +- src/hir_lints/mod.rs | 1 + src/hir_lints/pr_missing_newline.rs | 63 +++++++++++++++++++++++++++++ src/main.rs | 5 +++ src/rustdoc.rs | 12 ++++-- 7 files changed, 103 insertions(+), 5 deletions(-) create mode 100644 src/hir_lints/pr_missing_newline.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 4572b38..03d22f5 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -6,4 +6,4 @@ RUSTC_BOOTSTRAP = "1" [build] -rustflags = ["-Clinker-features=-lld"] +rustflags = ["-Zunstable-options", "-Clinker-features=-lld"] diff --git a/Cargo.lock b/Cargo.lock index 6269693..1689cf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,16 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +[[package]] +name = "cc" +version = "1.2.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" +dependencies = [ + "find-msvc-tools", + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.1" @@ -134,6 +144,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" + [[package]] name = "flate2" version = "1.1.5" @@ -298,6 +314,7 @@ version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f" dependencies = [ + "cc", "pkg-config", "vcpkg", ] @@ -543,6 +560,12 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "simd-adler32" version = "0.3.8" diff --git a/Cargo.toml b/Cargo.toml index db504d4..da32c46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT OR Apache-2.0" default-run = "klint" [dependencies] -rusqlite = "0.37" +rusqlite = { version = "0.37", features = ["bundled"] } home = "0.5" object = "0.38.0" gimli = "0.32.3" diff --git a/src/hir_lints/mod.rs b/src/hir_lints/mod.rs index ba03ed0..8a8ee10 100644 --- a/src/hir_lints/mod.rs +++ b/src/hir_lints/mod.rs @@ -1 +1,2 @@ pub(crate) mod not_using_prelude; +pub(crate) mod pr_missing_newline; diff --git a/src/hir_lints/pr_missing_newline.rs b/src/hir_lints/pr_missing_newline.rs new file mode 100644 index 0000000..6d63008 --- /dev/null +++ b/src/hir_lints/pr_missing_newline.rs @@ -0,0 +1,63 @@ +use rustc_ast::{MacCall, token}; +use rustc_ast::tokenstream::TokenTree; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + +declare_tool_lint! { + /// The `pr_missing_newline` lint detects `pr_*` calls that do not end with a newline. + pub klint::PR_MISSING_NEWLINE, + Warn, + "pr_* logging calls should end with a trailing \"\\n\"" +} + +pub struct PrMissingNewline; + +impl_lint_pass!(PrMissingNewline => [PR_MISSING_NEWLINE]); + +impl EarlyLintPass for PrMissingNewline { + fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) { + // Check if the macro path starts with "pr_" + if let Some(segment) = mac.path.segments.last() { + let name = segment.ident.as_str(); + if !name.starts_with("pr_") { + return; + } + if name == "pr_cont" { + return; + } + } else { + return; + } + + // We want to check the first argument of the macro. + // The arguments are in `mac.args`. This is a `MacArgs`. + // We usually expect `MacArgs::Delimited`. + + // `mac.args` appears to be `P` in this toolchain. + let tokens = &mac.args.tokens; + + // We need to look at the tokens to find the format string. + // This is a simplified check assuming the first token is a string literal. + // A robust check might need to parse the token stream, but for `pr_info!("str")` + // checking the first token tree is often enough if we skip whitespace/comments? + // Actually, `rustc_ast` usually gives us a stream. + + // We need to look at the tokens to find the format string. + for tt in tokens.iter() { + if let TokenTree::Token(token, _) = tt { + if let token::TokenKind::Literal(lit) = token.kind { + if matches!(lit.kind, token::LitKind::Str | token::LitKind::StrRaw(_)) { + let msg = lit.symbol.as_str(); + if !msg.ends_with('\n') { + cx.span_lint(PR_MISSING_NEWLINE, mac.span(), |diag| { + diag.primary_message("pr_* logging calls should end with a trailing \"\\n\""); + }); + } + // We found the format string, stop checking. + return; + } + } + } + } + } +} diff --git a/src/main.rs b/src/main.rs index 8c77b8c..8bf359f 100755 --- a/src/main.rs +++ b/src/main.rs @@ -121,6 +121,7 @@ impl Callbacks for MyCallbacks { atomic_context::ATOMIC_CONTEXT, binary_analysis::stack_size::STACK_FRAME_TOO_LARGE, hir_lints::not_using_prelude::NOT_USING_PRELUDE, + hir_lints::pr_missing_newline::PR_MISSING_NEWLINE, ]); lint_store.register_late_pass(|tcx| { @@ -129,6 +130,10 @@ impl Callbacks for MyCallbacks { }) }); + lint_store.register_early_pass(|| { + Box::new(hir_lints::pr_missing_newline::PrMissingNewline) + }); + // lint_store // .register_late_pass(|_| Box::new(infallible_allocation::InfallibleAllocation)); lint_store.register_late_pass(|tcx| { diff --git a/src/rustdoc.rs b/src/rustdoc.rs index 697685c..926d0b8 100644 --- a/src/rustdoc.rs +++ b/src/rustdoc.rs @@ -1,8 +1,14 @@ use std::io::Result; +#[cfg(unix)] use std::os::unix::process::CommandExt; fn main() -> Result<()> { - Err(std::process::Command::new(env!("RUSTDOC")) - .args(std::env::args().skip(1)) - .exec()) + let mut cmd = std::process::Command::new(env!("RUSTDOC")); + cmd.args(std::env::args().skip(1)); + + #[cfg(unix)] + return Err(cmd.exec()); + + #[cfg(not(unix))] + std::process::exit(cmd.status()?.code().unwrap_or(1)); } From 30c74e798fe221ac5b6e9789894c5af0b2dc397c Mon Sep 17 00:00:00 2001 From: ShigrafS Date: Sat, 31 Jan 2026 19:32:43 +0530 Subject: [PATCH 2/4] test(lints): add tests for pr_missing_newline --- tests/ui/pr_missing_newline.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/ui/pr_missing_newline.rs diff --git a/tests/ui/pr_missing_newline.rs b/tests/ui/pr_missing_newline.rs new file mode 100644 index 0000000..d225227 --- /dev/null +++ b/tests/ui/pr_missing_newline.rs @@ -0,0 +1,22 @@ +// check-pass + +#![feature(register_tool)] +#![register_tool(klint)] + +#[macro_export] +macro_rules! pr_info { + ($($arg:tt)*) => {}; +} + +#[macro_export] +macro_rules! pr_cont { + ($($arg:tt)*) => {}; +} + +fn main() { + pr_info!("hello"); //~ WARN pr_* logging calls should end with a trailing "\n" + pr_info!("hello\n"); + pr_cont!("hello"); + pr_info!("hello {}", "world"); //~ WARN pr_* logging calls should end with a trailing "\n" + pr_info!("hello {}\n", "world"); +} From a62ed40b7e646eb83ae1b15425fde6834f67b54d Mon Sep 17 00:00:00 2001 From: ShigrafS Date: Sat, 31 Jan 2026 19:57:31 +0530 Subject: [PATCH 3/4] fix(test): remove duplicate crate attributes in validation test Remove manual 'register_tool(klint)' attributes as they are already injected by the test harness, preventing 'already registered' errors during test execution. --- tests/ui/pr_missing_newline.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/ui/pr_missing_newline.rs b/tests/ui/pr_missing_newline.rs index d225227..808cf03 100644 --- a/tests/ui/pr_missing_newline.rs +++ b/tests/ui/pr_missing_newline.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(register_tool)] -#![register_tool(klint)] #[macro_export] macro_rules! pr_info { From dfe8c9e58ba6b0d00686657ecc874c2fd6ade631 Mon Sep 17 00:00:00 2001 From: ShigrafS Date: Sat, 31 Jan 2026 20:08:14 +0530 Subject: [PATCH 4/4] fix(lints): fix or suppress compiler warnings - Allow ustc::implicit_sysroot_crate_import in src/main.rs to support racing, itertools, and hiserror from sysroot. - Allow ustc::potential_query_instability in src/infallible_allocation.rs and src/monomorphize_collector.rs for deterministic iteration order issues. --- src/infallible_allocation.rs | 1 + src/main.rs | 2 ++ src/monomorphize_collector.rs | 1 + 3 files changed, 4 insertions(+) diff --git a/src/infallible_allocation.rs b/src/infallible_allocation.rs index 9625d91..7f4395a 100644 --- a/src/infallible_allocation.rs +++ b/src/infallible_allocation.rs @@ -25,6 +25,7 @@ fn is_generic_fn<'tcx>(instance: Instance<'tcx>) -> bool { } impl<'tcx> LateLintPass<'tcx> for InfallibleAllocation { + #[allow(rustc::potential_query_instability)] fn check_crate(&mut self, cx: &LateContext<'tcx>) { // Collect all mono items to be codegened with this crate. Discard the inline map, it does // not contain enough information for us; we will collect them ourselves later. diff --git a/src/main.rs b/src/main.rs index 8bf359f..792644b 100755 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,8 @@ #![feature(unsize)] #![warn(rustc::internal)] +#![allow(rustc::implicit_sysroot_crate_import)] + #[macro_use] extern crate rustc_macros; #[macro_use] diff --git a/src/monomorphize_collector.rs b/src/monomorphize_collector.rs index 7e67d6b..3a1cdd2 100644 --- a/src/monomorphize_collector.rs +++ b/src/monomorphize_collector.rs @@ -131,6 +131,7 @@ impl<'tcx> UsageMap<'tcx> { } // Internally iterate over all items and the things each accesses. + #[allow(rustc::potential_query_instability)] pub fn for_each_item_and_its_used_items(&self, mut f: F) where F: FnMut(MonoItem<'tcx>, &[Spanned>]),