From 44f8f4b25579a1d7aa75c30ceb2a6c28d0776296 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Fri, 12 Dec 2025 14:41:11 -0500 Subject: [PATCH 01/10] Split `is_msvc_link_exe` into a function --- compiler/rustc_codegen_ssa/src/back/link.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index fa730bae610cd..d911b4e6f5566 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -670,6 +670,14 @@ struct LinkerOutput { inner: String, } +fn is_msvc_link_exe(sess: &Session) -> bool { + let (linker_path, flavor) = linker_and_flavor(sess); + sess.target.is_like_msvc + && flavor == LinkerFlavor::Msvc(Lld::No) + // Match exactly "link.exe" + && linker_path.to_str() == Some("link.exe") +} + /// Create a dynamic library or executable. /// /// This will invoke the system linker/cc to create the resulting file. This links to all upstream @@ -856,11 +864,6 @@ fn link_natively( match prog { Ok(prog) => { - let is_msvc_link_exe = sess.target.is_like_msvc - && flavor == LinkerFlavor::Msvc(Lld::No) - // Match exactly "link.exe" - && linker_path.to_str() == Some("link.exe"); - if !prog.status.success() { let mut output = prog.stderr.clone(); output.extend_from_slice(&prog.stdout); @@ -880,7 +883,7 @@ fn link_natively( if let Some(code) = prog.status.code() { // All Microsoft `link.exe` linking ror codes are // four digit numbers in the range 1000 to 9999 inclusive - if is_msvc_link_exe && (code < 1000 || code > 9999) { + if is_msvc_link_exe(sess) && (code < 1000 || code > 9999) { let is_vs_installed = find_msvc_tools::find_vs_version().is_ok(); let has_linker = find_msvc_tools::find_tool(sess.target.arch.desc(), "link.exe") @@ -919,7 +922,7 @@ fn link_natively( // Hide some progress messages from link.exe that we don't care about. // See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146 - if is_msvc_link_exe { + if is_msvc_link_exe(sess) { if let Ok(str) = str::from_utf8(&prog.stdout) { let mut output = String::with_capacity(str.len()); for line in stdout.lines() { From e0974e7cf955e297c4ccca7ebe85cda7b860eb78 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Fri, 12 Dec 2025 14:54:07 -0500 Subject: [PATCH 02/10] Split `report_linker_output` into its own function --- compiler/rustc_codegen_ssa/src/back/link.rs | 90 +++++++++++---------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index d911b4e6f5566..ead51fb892dba 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -60,7 +60,7 @@ use super::rpath::{self, RPathConfig}; use super::{apple, versioned_llvm_target}; use crate::base::needs_allocator_shim_for_linking; use crate::{ - CodegenResults, CompiledModule, CrateInfo, NativeLib, errors, looks_like_rust_object_file, + CodegenLintLevels, CodegenResults, CompiledModule, CrateInfo, NativeLib, errors, looks_like_rust_object_file }; pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) { @@ -678,6 +678,51 @@ fn is_msvc_link_exe(sess: &Session) -> bool { && linker_path.to_str() == Some("link.exe") } +fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8], stderr: &[u8]) { + let escaped_stderr = escape_string(&stderr); + let mut escaped_stdout = escape_string(&stdout); + info!("linker stderr:\n{}", &escaped_stderr); + info!("linker stdout:\n{}", &escaped_stdout); + + // Hide some progress messages from link.exe that we don't care about. + // See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146 + if is_msvc_link_exe(sess) { + if let Ok(str) = str::from_utf8(&stdout) { + let mut output = String::with_capacity(str.len()); + for line in str.lines() { + if line.starts_with(" Creating library") + || line.starts_with("Generating code") + || line.starts_with("Finished generating code") + { + continue; + } else { + output += line; + output += "\r\n" + } + } + escaped_stdout = escape_string(output.trim().as_bytes()) + } + } + + let lint_msg = |msg| { + lint_level(sess, LINKER_MESSAGES, levels.linker_messages, None, |diag| { + LinkerOutput { inner: msg }.decorate_lint(diag) + }) + }; + + if !escaped_stderr.is_empty() { + // We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present. + let stderr = escaped_stderr + .strip_prefix("warning: ") + .unwrap_or(&escaped_stderr) + .replace(": warning: ", ": "); + lint_msg(format!("linker stderr: {stderr}")); + } + if !escaped_stdout.is_empty() { + lint_msg(format!("linker stdout: {}", escaped_stdout)) + } +} + /// Create a dynamic library or executable. /// /// This will invoke the system linker/cc to create the resulting file. This links to all upstream @@ -915,48 +960,7 @@ fn link_natively( sess.dcx().abort_if_errors(); } - let stderr = escape_string(&prog.stderr); - let mut stdout = escape_string(&prog.stdout); - info!("linker stderr:\n{}", &stderr); - info!("linker stdout:\n{}", &stdout); - - // Hide some progress messages from link.exe that we don't care about. - // See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146 - if is_msvc_link_exe(sess) { - if let Ok(str) = str::from_utf8(&prog.stdout) { - let mut output = String::with_capacity(str.len()); - for line in stdout.lines() { - if line.starts_with(" Creating library") - || line.starts_with("Generating code") - || line.starts_with("Finished generating code") - { - continue; - } - output += line; - output += "\r\n" - } - stdout = escape_string(output.trim().as_bytes()) - } - } - - let level = codegen_results.crate_info.lint_levels.linker_messages; - let lint = |msg| { - lint_level(sess, LINKER_MESSAGES, level, None, |diag| { - LinkerOutput { inner: msg }.decorate_lint(diag) - }) - }; - - if !prog.stderr.is_empty() { - // We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present. - let stderr = stderr - .strip_prefix("warning: ") - .unwrap_or(&stderr) - .replace(": warning: ", ": "); - lint(format!("linker stderr: {stderr}")); - } - if !stdout.is_empty() { - lint(format!("linker stdout: {}", stdout)) - } + report_linker_output(sess, codegen_results.crate_info.lint_levels, &prog.stdout, &prog.stderr); } Err(e) => { let linker_not_found = e.kind() == io::ErrorKind::NotFound; From 9ae9fa9778971c37b30f85048db3f6d134f52040 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Fri, 12 Dec 2025 17:17:24 -0500 Subject: [PATCH 03/10] Split out linker-info from linker-messages - Hide common linker output behind `linker-info` - Add tests - Account for different capitalization on windows-gnu when removing "warning" prefix --- compiler/rustc_codegen_ssa/src/back/link.rs | 121 +++++++++++++++--- compiler/rustc_codegen_ssa/src/lib.rs | 7 +- compiler/rustc_lint_defs/src/builtin.rs | 35 +++++ compiler/rustc_passes/messages.ftl | 2 +- compiler/rustc_passes/src/check_attr.rs | 4 +- compiler/rustc_span/src/symbol.rs | 1 + tests/ui/linking/macos-ignoring-duplicate.rs | 6 + .../linking/macos-ignoring-duplicate.stderr | 11 ++ tests/ui/linking/macos-search-path.rs | 6 + tests/ui/linking/macos-search-path.stderr | 11 ++ .../linking/windows-gnu-corrupt-drective.rs | 5 + .../windows-gnu-corrupt-drective.stderr | 12 ++ 12 files changed, 198 insertions(+), 23 deletions(-) create mode 100644 tests/ui/linking/macos-ignoring-duplicate.rs create mode 100644 tests/ui/linking/macos-ignoring-duplicate.stderr create mode 100644 tests/ui/linking/macos-search-path.rs create mode 100644 tests/ui/linking/macos-search-path.stderr create mode 100644 tests/ui/linking/windows-gnu-corrupt-drective.rs create mode 100644 tests/ui/linking/windows-gnu-corrupt-drective.stderr diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ead51fb892dba..cf4ed7533a042 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -22,6 +22,7 @@ use rustc_errors::{DiagCtxtHandle, LintDiagnostic}; use rustc_fs_util::{TempDirBuilder, fix_windows_verbatim_for_gcc, try_canonicalize}; use rustc_hir::attrs::NativeLibKind; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; +use rustc_lint_defs::builtin::LINKER_INFO; use rustc_macros::LintDiagnostic; use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file}; use rustc_metadata::{ @@ -60,7 +61,8 @@ use super::rpath::{self, RPathConfig}; use super::{apple, versioned_llvm_target}; use crate::base::needs_allocator_shim_for_linking; use crate::{ - CodegenLintLevels, CodegenResults, CompiledModule, CrateInfo, NativeLib, errors, looks_like_rust_object_file + CodegenLintLevels, CodegenResults, CompiledModule, CrateInfo, NativeLib, errors, + looks_like_rust_object_file, }; pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) { @@ -678,30 +680,94 @@ fn is_msvc_link_exe(sess: &Session) -> bool { && linker_path.to_str() == Some("link.exe") } +fn is_macos_ld(sess: &Session) -> bool { + let (_, flavor) = linker_and_flavor(sess); + sess.target.is_like_darwin && matches!(flavor, LinkerFlavor::Darwin(_, Lld::No)) +} + +fn is_windows_gnu_ld(sess: &Session) -> bool { + let (_, flavor) = linker_and_flavor(sess); + sess.target.is_like_windows + && !sess.target.is_like_msvc + && matches!(flavor, LinkerFlavor::Gnu(_, Lld::No)) +} + fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8], stderr: &[u8]) { - let escaped_stderr = escape_string(&stderr); + let mut escaped_stderr = escape_string(&stderr); let mut escaped_stdout = escape_string(&stdout); + let mut linker_info = String::new(); + info!("linker stderr:\n{}", &escaped_stderr); info!("linker stdout:\n{}", &escaped_stdout); + fn for_each(bytes: &[u8], mut f: impl FnMut(&str, &mut String)) -> String { + let mut output = String::new(); + if let Ok(str) = str::from_utf8(bytes) { + info!("line: {str}"); + output = String::with_capacity(str.len()); + for line in str.lines() { + f(line.trim(), &mut output); + } + } + escape_string(output.trim().as_bytes()) + } + // Hide some progress messages from link.exe that we don't care about. // See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146 if is_msvc_link_exe(sess) { - if let Ok(str) = str::from_utf8(&stdout) { - let mut output = String::with_capacity(str.len()); - for line in str.lines() { - if line.starts_with(" Creating library") - || line.starts_with("Generating code") - || line.starts_with("Finished generating code") - { - continue; - } else { - output += line; - output += "\r\n" - } + escaped_stdout = for_each(&stdout, |line, output| { + if line.starts_with(" Creating library") + || line.starts_with("Generating code") + || line.starts_with("Finished generating code") + { + linker_info += line; + linker_info += "\r\n"; + } else { + *output += line; + *output += "\r\n" } - escaped_stdout = escape_string(output.trim().as_bytes()) - } + }); + } else if is_macos_ld(sess) { + let deployment_mismatch = |line: &str| { + line.starts_with("ld: warning: object file (") + && line.contains("was built for newer 'macOS' version") + && line.contains("than being linked") + }; + let search_path = |line: &str| { + line.starts_with("ld: warning: search path '") && line.ends_with("' not found") + }; + escaped_stderr = for_each(&stderr, |line, output| { + if line.starts_with("ld: warning: ignoring duplicate libraries: ") + || deployment_mismatch(line) + || search_path(line) + { + linker_info += line; + linker_info += "\n"; + } else { + *output += line; + *output += "\n" + } + }); + } else if is_windows_gnu_ld(sess) { + let mut saw_exclude_symbol = false; + let exclude_symbols = |line: &str| { + line.starts_with("Warning: .drectve `-exclude-symbols:") + && line.ends_with("' unrecognized") + }; + // FIXME: are we sure this is stderr and not stdout? + escaped_stderr = for_each(&stderr, |line, output| { + if exclude_symbols(line) { + saw_exclude_symbol = true; + linker_info += line; + linker_info += "\n"; + } else if saw_exclude_symbol && line == "Warning: corrupt .drectve at end of def file" { + linker_info += line; + linker_info += "\n"; + } else { + *output += line; + *output += "\n" + } + }); } let lint_msg = |msg| { @@ -709,18 +775,28 @@ fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8] LinkerOutput { inner: msg }.decorate_lint(diag) }) }; + let lint_info = |msg| { + lint_level(sess, LINKER_INFO, levels.linker_info, None, |diag| { + LinkerOutput { inner: msg }.decorate_lint(diag) + }) + }; if !escaped_stderr.is_empty() { // We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present. - let stderr = escaped_stderr - .strip_prefix("warning: ") + escaped_stderr = + escaped_stderr.strip_prefix("warning: ").unwrap_or(&escaped_stderr).to_owned(); + escaped_stderr = escaped_stderr + .strip_prefix("Warning: ") .unwrap_or(&escaped_stderr) .replace(": warning: ", ": "); - lint_msg(format!("linker stderr: {stderr}")); + lint_msg(format!("linker stderr: {escaped_stderr}")); } if !escaped_stdout.is_empty() { lint_msg(format!("linker stdout: {}", escaped_stdout)) } + if !linker_info.is_empty() { + lint_info(linker_info); + } } /// Create a dynamic library or executable. @@ -960,7 +1036,12 @@ fn link_natively( sess.dcx().abort_if_errors(); } - report_linker_output(sess, codegen_results.crate_info.lint_levels, &prog.stdout, &prog.stderr); + report_linker_output( + sess, + codegen_results.crate_info.lint_levels, + &prog.stdout, + &prog.stderr, + ); } Err(e) => { let linker_not_found = e.kind() == io::ErrorKind::NotFound; diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index db8706d02ae1f..bdbe28d8a58ab 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -26,6 +26,7 @@ use rustc_data_structures::unord::UnordMap; use rustc_hir::CRATE_HIR_ID; use rustc_hir::attrs::{CfgEntry, NativeLibKind}; use rustc_hir::def_id::CrateNum; +use rustc_lint_defs::builtin::LINKER_INFO; use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::WorkProduct; @@ -360,10 +361,14 @@ impl CodegenResults { #[derive(Copy, Clone, Debug, Encodable, Decodable)] pub struct CodegenLintLevels { linker_messages: LevelAndSource, + linker_info: LevelAndSource, } impl CodegenLintLevels { pub fn from_tcx(tcx: TyCtxt<'_>) -> Self { - Self { linker_messages: tcx.lint_level_at_node(LINKER_MESSAGES, CRATE_HIR_ID) } + Self { + linker_messages: tcx.lint_level_at_node(LINKER_MESSAGES, CRATE_HIR_ID), + linker_info: tcx.lint_level_at_node(LINKER_INFO, CRATE_HIR_ID), + } } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 86aa6341aff87..69239567ee3e2 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -58,6 +58,7 @@ declare_lint_pass! { LARGE_ASSIGNMENTS, LATE_BOUND_LIFETIME_ARGUMENTS, LEGACY_DERIVE_HELPERS, + LINKER_INFO, LINKER_MESSAGES, LONG_RUNNING_CONST_EVAL, LOSSY_PROVENANCE_CASTS, @@ -4014,6 +4015,40 @@ declare_lint! { "warnings emitted at runtime by the target-specific linker program" } +declare_lint! { + /// The `linker_info` lint forwards warnings from the linker that are known to be informational-only. + /// + /// ### Example + /// + /// ```rust,ignore (needs CLI args, platform-specific) + /// #[warn(linker_info)] + /// fn main () {} + /// ``` + /// + /// On MacOS, using `-C link-arg=-lc` and the default linker, this will produce + /// + /// ```text + /// warning: linker stderr: ld: ignoring duplicate libraries: '-lc' + /// | + /// note: the lint level is defined here + /// --> ex.rs:1:9 + /// | + /// 1 | #![warn(linker_info)] + /// | ^^^^^^^^^^^^^^^ + /// ``` + /// + /// ### Explanation + /// + /// Many linkers are very "chatty" and print lots of information that is not necessarily + /// indicative of an issue. This output has been ignored for many years and is often not + /// actionable by developers. It is silenced unless the developer specifically requests for it + /// to be printed. See this tracking issue for more details: + /// . + pub LINKER_INFO, + Allow, + "linker warnings known to be informational-only and not indicative of a problem" +} + declare_lint! { /// The `named_arguments_used_positionally` lint detects cases where named arguments are only /// used positionally in format strings. This usage is valid but potentially very confusing. diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index c668bf0733d14..56e6ad999481f 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -642,7 +642,7 @@ passes_unused_empty_lints_note = attribute `{$name}` with an empty list has no effect passes_unused_linker_messages_note = - the `linker_messages` lint can only be controlled at the root of a crate that needs to be linked + the `linker_messages` and `linker_info` lints can only be controlled at the root of a crate that needs to be linked passes_unused_multiple = multiple `{$name}` attributes diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5944a1e8da5d1..db4d2ca3e8aa6 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1947,7 +1947,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect]) && let Some(meta) = attr.meta_item_list() && meta.iter().any(|meta| { - meta.meta_item().map_or(false, |item| item.path == sym::linker_messages) + meta.meta_item().map_or(false, |item| { + item.path == sym::linker_messages || item.path == sym::linker_info + }) }) { if hir_id != CRATE_HIR_ID { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 38718bad9e57e..ff7a15ee2d183 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1328,6 +1328,7 @@ symbols! { link_section, linkage, linker, + linker_info, linker_messages, linkonce, linkonce_odr, diff --git a/tests/ui/linking/macos-ignoring-duplicate.rs b/tests/ui/linking/macos-ignoring-duplicate.rs new file mode 100644 index 0000000000000..0c9241c8ee195 --- /dev/null +++ b/tests/ui/linking/macos-ignoring-duplicate.rs @@ -0,0 +1,6 @@ +//@ only-apple +//@ compile-flags: -C link-arg=-lc -C link-arg=-lc +//@ build-fail +#![deny(linker_info)] +//~? ERROR ignoring duplicate libraries +fn main() {} diff --git a/tests/ui/linking/macos-ignoring-duplicate.stderr b/tests/ui/linking/macos-ignoring-duplicate.stderr new file mode 100644 index 0000000000000..9037e8f4e391b --- /dev/null +++ b/tests/ui/linking/macos-ignoring-duplicate.stderr @@ -0,0 +1,11 @@ +error: ld: warning: ignoring duplicate libraries: '-lc' + + | +note: the lint level is defined here + --> $DIR/macos-ignoring-duplicate.rs:4:9 + | +LL | #![deny(linker_info)] + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/linking/macos-search-path.rs b/tests/ui/linking/macos-search-path.rs new file mode 100644 index 0000000000000..6d3e420bcdf6d --- /dev/null +++ b/tests/ui/linking/macos-search-path.rs @@ -0,0 +1,6 @@ +//@ only-apple +//@ compile-flags: -C link-arg=-Wl,-L/no/such/file/or/directory +//@ build-fail +#![deny(linker_info)] +//~? ERROR search path +fn main() {} diff --git a/tests/ui/linking/macos-search-path.stderr b/tests/ui/linking/macos-search-path.stderr new file mode 100644 index 0000000000000..598036d0d403e --- /dev/null +++ b/tests/ui/linking/macos-search-path.stderr @@ -0,0 +1,11 @@ +error: ld: warning: search path '/no/such/file/or/directory' not found + + | +note: the lint level is defined here + --> $DIR/macos-search-path.rs:4:9 + | +LL | #![deny(linker_info)] + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/linking/windows-gnu-corrupt-drective.rs b/tests/ui/linking/windows-gnu-corrupt-drective.rs new file mode 100644 index 0000000000000..45151a380d262 --- /dev/null +++ b/tests/ui/linking/windows-gnu-corrupt-drective.rs @@ -0,0 +1,5 @@ +//@ only-windows-gnu +//@ build-fail +#![deny(linker_info)] +//~? ERROR Warning: .drectve +fn main() {} diff --git a/tests/ui/linking/windows-gnu-corrupt-drective.stderr b/tests/ui/linking/windows-gnu-corrupt-drective.stderr new file mode 100644 index 0000000000000..07e800ee836d5 --- /dev/null +++ b/tests/ui/linking/windows-gnu-corrupt-drective.stderr @@ -0,0 +1,12 @@ +error: Warning: .drectve `-exclude-symbols:_ZN28windows_gnu_corrupt_drective4main17h291ed884c1aada69E ' unrecognized + Warning: corrupt .drectve at end of def file + + | +note: the lint level is defined here + --> $DIR/windows-gnu-corrupt-drective.rs:3:9 + | +LL | #![deny(linker_info)] + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error + From 3efd42c6b56e8ecde4296087eea7efda6ac9015f Mon Sep 17 00:00:00 2001 From: jyn Date: Fri, 12 Dec 2025 19:48:45 -0500 Subject: [PATCH 04/10] Set linker-messages to warn-by-default --- compiler/rustc_lint_defs/src/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 69239567ee3e2..2a519f6594cbc 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4011,7 +4011,7 @@ declare_lint! { /// and actionable warning of similar quality to our other diagnostics. See this tracking /// issue for more details: . pub LINKER_MESSAGES, - Allow, + Warn, "warnings emitted at runtime by the target-specific linker program" } From c60bee57b76e2bd81d91340f06c8f553afacbabe Mon Sep 17 00:00:00 2001 From: jyn Date: Fri, 12 Dec 2025 21:27:43 -0500 Subject: [PATCH 05/10] bles --- tests/ui/lint/linker-warning.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/lint/linker-warning.stderr b/tests/ui/lint/linker-warning.stderr index ae5f6b3adece0..54994c48ea43a 100644 --- a/tests/ui/lint/linker-warning.stderr +++ b/tests/ui/lint/linker-warning.stderr @@ -20,7 +20,7 @@ warning: unused attribute LL | #![allow(linker_messages)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | - = note: the `linker_messages` lint can only be controlled at the root of a crate that needs to be linked + = note: the `linker_messages` and `linker_info` lints can only be controlled at the root of a crate that needs to be linked warning: 2 warnings emitted From 3062f507aac136c8bb442bf513d7fbf0849bf184 Mon Sep 17 00:00:00 2001 From: jyn Date: Sat, 13 Dec 2025 10:25:11 -0500 Subject: [PATCH 06/10] set messages=deny for crater --- compiler/rustc_lint_defs/src/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 2a519f6594cbc..4c1bb72e6f1f3 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4011,7 +4011,7 @@ declare_lint! { /// and actionable warning of similar quality to our other diagnostics. See this tracking /// issue for more details: . pub LINKER_MESSAGES, - Warn, + Deny, "warnings emitted at runtime by the target-specific linker program" } From f1e7002182d085b3343be91537cdca6582e6efdb Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Sat, 13 Dec 2025 18:00:47 -0500 Subject: [PATCH 07/10] add macOS deployment-target test --- .../macos-deployment-target-warning/foo.c | 1 + .../macos-deployment-target-warning/main.rs | 8 +++++ .../macos-deployment-target-warning/rmake.rs | 29 +++++++++++++++++++ .../warnings.txt | 11 +++++++ 4 files changed, 49 insertions(+) create mode 100644 tests/run-make/macos-deployment-target-warning/foo.c create mode 100644 tests/run-make/macos-deployment-target-warning/main.rs create mode 100644 tests/run-make/macos-deployment-target-warning/rmake.rs create mode 100644 tests/run-make/macos-deployment-target-warning/warnings.txt diff --git a/tests/run-make/macos-deployment-target-warning/foo.c b/tests/run-make/macos-deployment-target-warning/foo.c new file mode 100644 index 0000000000000..85e6cd8c3909a --- /dev/null +++ b/tests/run-make/macos-deployment-target-warning/foo.c @@ -0,0 +1 @@ +void foo() {} diff --git a/tests/run-make/macos-deployment-target-warning/main.rs b/tests/run-make/macos-deployment-target-warning/main.rs new file mode 100644 index 0000000000000..2c3be92812e12 --- /dev/null +++ b/tests/run-make/macos-deployment-target-warning/main.rs @@ -0,0 +1,8 @@ +#![warn(linker_info, linker_messages)] +unsafe extern "C" { + safe fn foo(); +} + +fn main() { + foo(); +} diff --git a/tests/run-make/macos-deployment-target-warning/rmake.rs b/tests/run-make/macos-deployment-target-warning/rmake.rs new file mode 100644 index 0000000000000..e109b2adcc17a --- /dev/null +++ b/tests/run-make/macos-deployment-target-warning/rmake.rs @@ -0,0 +1,29 @@ +//@ only-apple +//! Tests that deployment target linker warnings are shown as `linker-info`, not `linker-messages` + +use run_make_support::external_deps::c_cxx_compiler::cc; +use run_make_support::external_deps::llvm::llvm_ar; +use run_make_support::{bare_rustc, diff}; + +fn main() { + let cwd = std::env::current_dir().unwrap().to_str().unwrap().to_owned(); + + cc().arg("-c").arg("-mmacosx-version-min=15.5").output("foo.o").input("foo.c").run(); + llvm_ar().obj_to_ar().output_input("libfoo.a", "foo.o").run(); + + let warnings = bare_rustc() + .arg("-L") + .arg(format!("native={cwd}")) + .arg("-lstatic=foo") + .link_arg("-mmacosx-version-min=11.2") + .input("main.rs") + .crate_type("bin") + .run() + .stderr_utf8(); + + diff() + .expected_file("warnings.txt") + .actual_text("(rustc -W linker-info)", &warnings) + .normalize(r"\(.*/rmake_out/", "(TEST_DIR/") + .run() +} diff --git a/tests/run-make/macos-deployment-target-warning/warnings.txt b/tests/run-make/macos-deployment-target-warning/warnings.txt new file mode 100644 index 0000000000000..ab08c6d9ae5b2 --- /dev/null +++ b/tests/run-make/macos-deployment-target-warning/warnings.txt @@ -0,0 +1,11 @@ +warning: ld: warning: object file (TEST_DIR/libfoo.a[2](foo.o)) was built for newer 'macOS' version (15.5) than being linked (11.2) + + | +note: the lint level is defined here + --> main.rs:1:9 + | +1 | #![warn(linker_info, linker_messages)] + | ^^^^^^^^^^^ + +warning: 1 warning emitted + From 474f558d2db42cc7f97dea3c390c5de0892618d1 Mon Sep 17 00:00:00 2001 From: jyn Date: Sun, 14 Dec 2025 00:28:06 +0000 Subject: [PATCH 08/10] ok this was just not worth my time, got it --- tests/ui/process/nofile-limit.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/ui/process/nofile-limit.rs b/tests/ui/process/nofile-limit.rs index 64777b514256e..f5246856b80f2 100644 --- a/tests/ui/process/nofile-limit.rs +++ b/tests/ui/process/nofile-limit.rs @@ -11,6 +11,9 @@ #![feature(exit_status_error)] #![feature(rustc_private)] +// on aarch64, "Using 'getaddrinfo' in statically linked applications requires at runtime the shared +// libraries from the glibc version used for linking" +#![allow(linker_messages)] extern crate libc; use std::os::unix::process::CommandExt; From 245d964830b9a5be8cd4466f7185abf2c36ded54 Mon Sep 17 00:00:00 2001 From: jyn Date: Sat, 13 Dec 2025 19:35:08 -0500 Subject: [PATCH 09/10] add some more comments --- compiler/rustc_codegen_ssa/src/back/link.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index cf4ed7533a042..41232f9f515de 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -712,10 +712,10 @@ fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8] escape_string(output.trim().as_bytes()) } - // Hide some progress messages from link.exe that we don't care about. - // See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146 if is_msvc_link_exe(sess) { escaped_stdout = for_each(&stdout, |line, output| { + // Hide some progress messages from link.exe that we don't care about. + // See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146 if line.starts_with(" Creating library") || line.starts_with("Generating code") || line.starts_with("Finished generating code") @@ -728,15 +728,19 @@ fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8] } }); } else if is_macos_ld(sess) { + // FIXME: Tracked by https://github.com/rust-lang/rust/issues/136113 let deployment_mismatch = |line: &str| { line.starts_with("ld: warning: object file (") && line.contains("was built for newer 'macOS' version") && line.contains("than being linked") }; + // FIXME: This is a real warning we would like to show, but it hits too many crates + // to want to turn it on immediately. let search_path = |line: &str| { line.starts_with("ld: warning: search path '") && line.ends_with("' not found") }; escaped_stderr = for_each(&stderr, |line, output| { + // This duplicate library warning is just not helpful at all. if line.starts_with("ld: warning: ignoring duplicate libraries: ") || deployment_mismatch(line) || search_path(line) @@ -750,11 +754,12 @@ fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8] }); } else if is_windows_gnu_ld(sess) { let mut saw_exclude_symbol = false; + // See https://github.com/rust-lang/rust/issues/112368. + // FIXME: maybe check that binutils is older than 2.40 before downgrading this warning? let exclude_symbols = |line: &str| { line.starts_with("Warning: .drectve `-exclude-symbols:") && line.ends_with("' unrecognized") }; - // FIXME: are we sure this is stderr and not stdout? escaped_stderr = for_each(&stderr, |line, output| { if exclude_symbols(line) { saw_exclude_symbol = true; @@ -785,6 +790,7 @@ fn report_linker_output(sess: &Session, levels: CodegenLintLevels, stdout: &[u8] // We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present. escaped_stderr = escaped_stderr.strip_prefix("warning: ").unwrap_or(&escaped_stderr).to_owned(); + // Windows GNU LD prints uppercase Warning escaped_stderr = escaped_stderr .strip_prefix("Warning: ") .unwrap_or(&escaped_stderr) From 36a42da665fed8a825dc4104f62d3b6e7b835a24 Mon Sep 17 00:00:00 2001 From: jyn Date: Sat, 13 Dec 2025 20:23:20 -0500 Subject: [PATCH 10/10] don't use no_main and no_core to test IBT --- tests/run-make/branch-protection-check-IBT/lib.rs | 1 + tests/run-make/branch-protection-check-IBT/main.rs | 5 ----- tests/run-make/branch-protection-check-IBT/rmake.rs | 6 ++++-- 3 files changed, 5 insertions(+), 7 deletions(-) create mode 100644 tests/run-make/branch-protection-check-IBT/lib.rs delete mode 100644 tests/run-make/branch-protection-check-IBT/main.rs diff --git a/tests/run-make/branch-protection-check-IBT/lib.rs b/tests/run-make/branch-protection-check-IBT/lib.rs new file mode 100644 index 0000000000000..0c9ac1ac8e4bd --- /dev/null +++ b/tests/run-make/branch-protection-check-IBT/lib.rs @@ -0,0 +1 @@ +#![no_std] diff --git a/tests/run-make/branch-protection-check-IBT/main.rs b/tests/run-make/branch-protection-check-IBT/main.rs deleted file mode 100644 index 445b8795134c5..0000000000000 --- a/tests/run-make/branch-protection-check-IBT/main.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![feature(no_core)] -#![allow(internal_features)] -#![no_core] -#![no_std] -#![no_main] diff --git a/tests/run-make/branch-protection-check-IBT/rmake.rs b/tests/run-make/branch-protection-check-IBT/rmake.rs index 73109df12ae9d..b2a96940111f1 100644 --- a/tests/run-make/branch-protection-check-IBT/rmake.rs +++ b/tests/run-make/branch-protection-check-IBT/rmake.rs @@ -43,11 +43,13 @@ use run_make_support::{bare_rustc, llvm_readobj}; fn main() { // `main.rs` is `#![no_std]` to not pull in the currently not-compiled-with-IBT precompiled std. bare_rustc() - .input("main.rs") + .input("lib.rs") + .crate_type("lib") + .emit("obj=lib.o") .target("x86_64-unknown-linux-gnu") .arg("-Zcf-protection=branch") .arg("-Clink-args=-nostartfiles") .run(); - llvm_readobj().arg("-nW").input("main").run().assert_stdout_contains(".note.gnu.property"); + llvm_readobj().arg("-nW").input("lib.o").run().assert_stdout_contains(".note.gnu.property"); }