authorbors <bors@rust-lang.org> 2026-05-01 17:15:17 UTC
committerbors <bors@rust-lang.org> 2026-05-01 17:15:17 UTC
log67bcaa9c4b1b1015efae3d591155c79760b1e0a5
treea68bc9ed6335b623fa0f71e845f45a4772f14a4b
parent0164cc139285d5452053bcc5a83da046a501ed61
parent4e99b682ce126f0f8e736d110474baf0acb9c989

Auto merge of #153968 - jyn514:jyn/linker-warn-by-default, r=mati865

linker-messages is warn-by-default again cc rust-lang/rust#136096 I ended up keeping it a lint and adding an option for lints to ignore `-Dwarnings` (there was already a lint that did that actually, it was just hard-coded in rustc_middle instead of in rustc_lint_defs like I'd expect). This allows people to actually see the warnings without them failing the build in CI.

11 files changed, 129 insertions(+), 18 deletions(-)

compiler/rustc_codegen_ssa/src/back/link.rs+27-6
......@@ -692,6 +692,15 @@ fn is_windows_gnu_ld(sess: &Session) -> bool {
692692 sess.target.is_like_windows
693693 && !sess.target.is_like_msvc
694694 && matches!(flavor, LinkerFlavor::Gnu(_, Lld::No))
695 && sess.target.options.cfg_abi != CfgAbi::Llvm
696}
697
698fn is_windows_gnu_clang(sess: &Session) -> bool {
699 let (_, flavor) = linker_and_flavor(sess);
700 sess.target.is_like_windows
701 && !sess.target.is_like_msvc
702 && matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, Lld::No))
703 && sess.target.options.cfg_abi == CfgAbi::Llvm
695704}
696705
697706fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8], stderr: &[u8]) {
......@@ -720,9 +729,10 @@ fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8]
720729 escaped_stdout = for_each(&stdout, |line, output| {
721730 // Hide some progress messages from link.exe that we don't care about.
722731 // See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146
723 if line.starts_with(" Creating library")
724 || line.starts_with("Generating code")
725 || line.starts_with("Finished generating code")
732 let trimmed = line.trim_start();
733 if trimmed.starts_with("Creating library")
734 || trimmed.starts_with("Generating code")
735 || trimmed.starts_with("Finished generating code")
726736 {
727737 linker_info += line;
728738 linker_info += "\r\n";
......@@ -781,7 +791,18 @@ fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8]
781791 *output += "\n"
782792 }
783793 });
784 }
794 } else if is_windows_gnu_clang(sess) {
795 info!("inferred Windows Clang (GNU ABI)");
796 escaped_stderr = for_each(&stderr, |line, output| {
797 if line.contains("argument unused during compilation: '-nolibc'") {
798 linker_info += line;
799 linker_info += "\n";
800 } else {
801 *output += line;
802 *output += "\n"
803 }
804 });
805 };
785806
786807 let lint_msg = |msg| {
787808 emit_lint_base(
......@@ -805,10 +826,10 @@ fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8]
805826 .strip_prefix("Warning: ")
806827 .unwrap_or(&escaped_stderr)
807828 .replace(": warning: ", ": ");
808 lint_msg(format!("linker stderr: {escaped_stderr}"));
829 lint_msg(format!("linker stderr: {}", escaped_stderr.trim_end()));
809830 }
810831 if !escaped_stdout.is_empty() {
811 lint_msg(format!("linker stdout: {}", escaped_stdout))
832 lint_msg(format!("linker stdout: {}", escaped_stdout.trim_end()))
812833 }
813834 if !linker_info.is_empty() {
814835 lint_info(linker_info);
compiler/rustc_lint_defs/src/builtin.rs+11-2
......@@ -193,6 +193,11 @@ declare_lint! {
193193 reason: fcw!(FutureReleaseError #81670),
194194 report_in_deps: true,
195195 };
196 // We exempt `FORBIDDEN_LINT_GROUPS` from `-Dwarnings` because it specifically
197 // triggers in cases (like #80988) where you have `forbid(warnings)`,
198 // and so if we turned that into an error, it'd defeat the purpose of the
199 // future compatibility warning.
200 ignore_deny_warnings
196201}
197202
198203declare_lint! {
......@@ -4073,8 +4078,12 @@ declare_lint! {
40734078 /// and actionable warning of similar quality to our other diagnostics. See this tracking
40744079 /// issue for more details: <https://github.com/rust-lang/rust/issues/136096>.
40754080 pub LINKER_MESSAGES,
4076 Allow,
4077 "warnings emitted at runtime by the target-specific linker program"
4081 Warn,
4082 "warnings emitted at runtime by the target-specific linker program",
4083 // Linker messages don't live up to the high standard people expect of rustc's errors.
4084 // Prevent `-D warnings` from applying to it.
4085 // It's still possible to pass `-D linker-messages` specifically.
4086 ignore_deny_warnings
40784087}
40794088
40804089declare_lint! {
compiler/rustc_lint_defs/src/lib.rs+4
......@@ -343,6 +343,9 @@ pub struct Lint {
343343 /// `true` if this lint should not be filtered out under any circustamces
344344 /// (e.g. the unknown_attributes lint)
345345 pub eval_always: bool,
346
347 /// `true` if this lint is unaffected by `-D warnings`
348 pub ignore_deny_warnings: bool,
346349}
347350
348351/// Extra information for a future incompatibility lint.
......@@ -558,6 +561,7 @@ impl Lint {
558561 feature_gate: None,
559562 crate_level_only: false,
560563 eval_always: false,
564 ignore_deny_warnings: false,
561565 }
562566 }
563567
compiler/rustc_middle/src/lint.rs+36-10
......@@ -7,8 +7,9 @@ use rustc_hir::{HirId, ItemLocalId};
77use rustc_lint_defs::EditionFcw;
88use rustc_macros::{Decodable, Encodable, HashStable};
99use rustc_session::Session;
10use rustc_session::lint::builtin::{self, FORBIDDEN_LINT_GROUPS};
11use rustc_session::lint::{FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId};
10use rustc_session::lint::{
11 FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId, builtin,
12};
1213use rustc_span::{DUMMY_SP, ExpnKind, Span, Symbol, kw};
1314use tracing::instrument;
1415
......@@ -89,17 +90,30 @@ pub fn reveal_actual_level(
8990 level.unwrap_or_else(|| (lint.lint.default_level(sess.edition()), None));
9091
9192 // If we're about to issue a warning, check at the last minute for any
92 // directives against the warnings "lint". If, for example, there's an
93 // directives against the `warnings` lint group. If, for example, there's an
9394 // `allow(warnings)` in scope then we want to respect that instead.
94 //
95 // We exempt `FORBIDDEN_LINT_GROUPS` from this because it specifically
96 // triggers in cases (like #80988) where you have `forbid(warnings)`,
97 // and so if we turned that into an error, it'd defeat the purpose of the
98 // future compatibility warning.
99 if level == Level::Warn && lint != LintId::of(FORBIDDEN_LINT_GROUPS) {
95 if level == Level::Warn {
10096 let (warnings_level, warnings_src) = probe_for_lint_level(LintId::of(builtin::WARNINGS));
10197 if let Some((configured_warning_level, configured_lint_id)) = warnings_level {
102 if configured_warning_level != Level::Warn {
98 let respect_warnings_lint_group = match configured_warning_level {
99 // -Wwarnings is a no-op.
100 Level::Warn => false,
101 // Some warnings cannot be denied from the `warnings` lint group, only individually.
102 Level::Deny | Level::Forbid => !lint.lint.ignore_deny_warnings,
103 // All warnings respect -Awarnings.
104 Level::Allow => true,
105 // Not sure what the right behavior is here, but, sure, why not.
106 // See tests/ui/lint/rfc-2383-lint-reason/expect_warnings.rs.
107 Level::Expect => true,
108 Level::ForceWarn => {
109 sess.dcx().span_delayed_bug(
110 warnings_src.span(),
111 "cannot --force-warn the `warnings` lint group",
112 );
113 false
114 }
115 };
116 if respect_warnings_lint_group {
103117 level = configured_warning_level;
104118 lint_id = configured_lint_id;
105119 *src = warnings_src;
......@@ -291,6 +305,18 @@ fn explain_lint_level_source(
291305 }
292306 }
293307 }
308
309 if let Some(warnings_group) = sess
310 .opts
311 .lint_opts
312 .iter()
313 .find_map(|(opt, level)| (opt == "warnings").then_some(level))
314 .copied()
315 && warnings_group >= Level::Deny
316 && level < warnings_group
317 {
318 err.note_once(format!("the `{name}` lint ignores `-D warnings`"));
319 }
294320}
295321
296322/// The innermost function for emitting lints implementing the [`trait@Diagnostic`] trait.
src/bootstrap/src/core/builder/cargo.rs+4
......@@ -344,6 +344,10 @@ impl Cargo {
344344 self.rustflags.arg("-Clink-arg=-gz");
345345 }
346346
347 // Ignore linker warnings for now. These are complicated to fix and don't affect the build.
348 // FIXME: we should really investigate these...
349 self.rustflags.arg("-Alinker-messages");
350
347351 // Throughout the build Cargo can execute a number of build scripts
348352 // compiling C/C++ code and we need to pass compilers, archivers, flags, etc
349353 // obtained previously to those build scripts.
src/tools/compiletest/src/directives/directive_names.rs+2
......@@ -143,6 +143,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
143143 "ignore-x86_64",
144144 "ignore-x86_64-apple-darwin",
145145 "ignore-x86_64-pc-windows-gnu",
146 "ignore-x86_64-pc-windows-gnullvm",
146147 "ignore-x86_64-unknown-linux-gnu",
147148 "incremental",
148149 "known-bug",
......@@ -268,6 +269,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
268269 "only-x86_64-apple-darwin",
269270 "only-x86_64-fortanix-unknown-sgx",
270271 "only-x86_64-pc-windows-gnu",
272 "only-x86_64-pc-windows-gnullvm",
271273 "only-x86_64-pc-windows-msvc",
272274 "only-x86_64-unknown-linux-gnu",
273275 "pp-exact",
tests/run-make/linker-warning/deny-linker-lint.txt created+6
......@@ -0,0 +1,6 @@
1error: linker stderr: bar
2 |
3 = note: requested on the command line with `-D linker-messages`
4
5error: aborting due to 1 previous error
6
tests/run-make/linker-warning/deny-warnings.txt created+7
......@@ -0,0 +1,7 @@
1warning: linker stderr: bar
2 |
3 = note: requested on the command line with `-W linker-messages`
4 = note: the `linker_messages` lint ignores `-D warnings`
5
6warning: 1 warning emitted
7
tests/run-make/linker-warning/rmake.rs+13
......@@ -37,6 +37,19 @@ fn main() {
3737 .run()
3838 .assert_stderr_contains("warning: linker stdout: foo");
3939
40 // Make sure it respects `-D linker-messages`
41 let out = run_rustc().link_arg("run_make_warn").arg("-Dlinker-messages").run_fail();
42 out.assert_stderr_contains("error: linker stderr: bar");
43 diff()
44 .expected_file("deny-linker-lint.txt")
45 .actual_text("(linker warning)", out.stderr())
46 .run();
47
48 // Make sure that linker warnings don't fail the build when `-D warnings` is present.
49 let out = run_rustc().link_arg("run_make_warn").arg("-Dwarnings").run();
50 out.assert_stderr_contains("warning: linker stderr: bar");
51 diff().expected_file("deny-warnings.txt").actual_text("(linker warning)", out.stderr()).run();
52
4053 // Make sure we short-circuit this new path if the linker exits with an error
4154 // (so the diagnostic is less verbose)
4255 run_rustc().link_arg("run_make_error").run_fail().assert_stderr_contains("note: error: baz");
tests/ui/linking/no-libc-mingw-llvm.rs created+8
......@@ -0,0 +1,8 @@
1//@ build-pass
2//@ only-x86_64-pc-windows-gnullvm
3#![allow(linker_messages)]
4#![warn(linker_info)]
5
6//~? WARN argument unused
7
8fn main() {}
tests/ui/linking/no-libc-mingw-llvm.stderr created+11
......@@ -0,0 +1,11 @@
1warning: clang: warning: argument unused during compilation: '-nolibc' [-Wunused-command-line-argument]
2
3 |
4note: the lint level is defined here
5 --> $DIR/no-libc-mingw-llvm.rs:4:9
6 |
7LL | #![warn(linker_info)]
8 | ^^^^^^^^^^^
9
10warning: 1 warning emitted
11