about summary refs log tree commit diff
diff options
context:
space:
mode:
authorjyn <github@jyn.dev>2024-10-16 01:14:10 -0400
committerjyn <github@jyn.dev>2025-01-20 16:46:00 -0500
commit537218afb2b7f6c8ef9793a52b45c73d1dcb4d4c (patch)
tree53101f705b0ff888445a6fa4b993853bc1e69349
parentc0822ed9b8807ff350e24377e9d1999cc28edf0f (diff)
downloadrust-537218afb2b7f6c8ef9793a52b45c73d1dcb4d4c.tar.gz
rust-537218afb2b7f6c8ef9793a52b45c73d1dcb4d4c.zip
make it possible to silence linker warnings with a crate-level attribute
this was slightly complicated because codegen_ssa doesn't have access to a tcx.
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs21
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs21
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs34
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs14
-rw-r--r--compiler/rustc_middle/src/lint.rs6
5 files changed, 85 insertions, 11 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 378b6a50f7f..80758aac134 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -15,13 +15,14 @@ use rustc_ast::CRATE_NODE_ID;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::temp_dir::MaybeTempDir;
-use rustc_errors::DiagCtxtHandle;
+use rustc_errors::{DiagCtxtHandle, LintDiagnostic};
 use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
-use rustc_macros::Diagnostic;
+use rustc_macros::LintDiagnostic;
 use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
 use rustc_metadata::{find_native_static_library, walk_native_lib_search_dirs};
 use rustc_middle::bug;
+use rustc_middle::lint::lint_level;
 use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
@@ -30,6 +31,7 @@ use rustc_session::config::{
     OutputType, PrintKind, SplitDwarfKind, Strip,
 };
 use rustc_session::cstore::DllImport;
+use rustc_session::lint::builtin::LINKER_MESSAGES;
 use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
 use rustc_session::search_paths::PathKind;
 use rustc_session::utils::NativeLibKind;
@@ -750,7 +752,7 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out
     }
 }
 
-#[derive(Diagnostic)]
+#[derive(LintDiagnostic)]
 #[diag(codegen_ssa_linker_output)]
 /// Translating this is kind of useless. We don't pass translation flags to the linker, so we'd just
 /// end up with inconsistent languages within the same diagnostic.
@@ -1038,6 +1040,13 @@ fn link_natively(
                 sess.dcx().abort_if_errors();
             }
 
+            let (level, src) = codegen_results.crate_info.lint_levels.linker_messages;
+            let lint = |msg| {
+                lint_level(sess, LINKER_MESSAGES, level, src, 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 = escape_string(&prog.stderr);
@@ -1046,12 +1055,10 @@ fn link_natively(
                     .strip_prefix("warning: ")
                     .unwrap_or(&stderr)
                     .replace(": warning: ", ": ");
-                sess.dcx().emit_warn(LinkerOutput { inner: format!("linker stderr: {stderr}") });
+                lint(format!("linker stderr: {stderr}"));
             }
             if !prog.stdout.is_empty() && sess.opts.verbose {
-                sess.dcx().emit_warn(LinkerOutput {
-                    inner: format!("linker stdout: {}", escape_string(&prog.stdout)),
-                });
+                lint(format!("linker stdout: {}", escape_string(&prog.stdout)))
             }
         }
         Err(e) => {
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 332f2ffbc88..40299ae2630 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -29,18 +29,23 @@ use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::unord::UnordMap;
+use rustc_hir::CRATE_HIR_ID;
 use rustc_hir::def_id::CrateNum;
 use rustc_macros::{Decodable, Encodable, HashStable};
 use rustc_middle::dep_graph::WorkProduct;
+use rustc_middle::lint::LintLevelSource;
 use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::middle::dependency_format::Dependencies;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
+use rustc_middle::ty::TyCtxt;
 use rustc_middle::util::Providers;
 use rustc_serialize::opaque::{FileEncoder, MemDecoder};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_session::Session;
 use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
 use rustc_session::cstore::{self, CrateSource};
+use rustc_session::lint::Level;
+use rustc_session::lint::builtin::LINKER_MESSAGES;
 use rustc_session::utils::NativeLibKind;
 use rustc_span::Symbol;
 
@@ -303,3 +308,19 @@ impl CodegenResults {
         Ok((codegen_results, outputs))
     }
 }
+
+/// A list of lint levels used in codegen.
+///
+/// When using `-Z link-only`, we don't have access to the tcx and must work
+/// solely from the `.rlink` file. `Lint`s are defined too early to be encodeable.
+/// Instead, encode exactly the information we need.
+#[derive(Copy, Clone, Debug, Encodable, Decodable)]
+pub struct CodegenLintLevels {
+    linker_messages: (Level, LintLevelSource),
+}
+
+impl CodegenLintLevels {
+    pub fn from_tcx(tcx: TyCtxt<'_>) -> Self {
+        Self { linker_messages: tcx.lint_level_at_node(LINKER_MESSAGES, CRATE_HIR_ID) }
+    }
+}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 9fc527a6a3a..5cdd18f5ea9 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -60,6 +60,7 @@ declare_lint_pass! {
         LARGE_ASSIGNMENTS,
         LATE_BOUND_LIFETIME_ARGUMENTS,
         LEGACY_DERIVE_HELPERS,
+        LINKER_MESSAGES,
         LONG_RUNNING_CONST_EVAL,
         LOSSY_PROVENANCE_CASTS,
         MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
@@ -4086,6 +4087,39 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `linker_messages` lint forwards warnings from the linker.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (needs CLI args, platform-specific)
+    /// extern "C" {
+    ///   fn foo();
+    /// }
+    /// fn main () { unsafe { foo(); } }
+    /// ```
+    ///
+    /// On Linux, using `gcc -Wl,--warn-unresolved-symbols` as a linker, this will produce
+    ///
+    /// ```text
+    /// warning: linker stderr: rust-lld: undefined symbol: foo
+    ///          >>> referenced by rust_out.69edbd30df4ae57d-cgu.0
+    ///          >>>               rust_out.rust_out.69edbd30df4ae57d-cgu.0.rcgu.o:(rust_out::main::h3a90094b06757803)
+    ///   |
+    ///   = note: `#[warn(linker_messages)]` on by default
+    ///
+    /// warning: 1 warning emitted
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// Linkers emit platform-specific and program-specific warnings that cannot be predicted in advance by the rust compiler.
+    /// They are forwarded by default, but can be disabled by adding `#![allow(linker_messages)]` at the crate root.
+    pub LINKER_MESSAGES,
+    Warn,
+    "warnings emitted at runtime by the target-specific linker program"
+}
+
+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_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 7786d3eb59a..9f4c5d89d0e 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -161,7 +161,19 @@ impl<HCX: rustc_hir::HashStableContext> ToStableHashKey<HCX> for LintExpectation
 /// Setting for how to handle a lint.
 ///
 /// See: <https://doc.rust-lang.org/rustc/lints/levels.html>
-#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, HashStable_Generic)]
+#[derive(
+    Clone,
+    Copy,
+    PartialEq,
+    PartialOrd,
+    Eq,
+    Ord,
+    Debug,
+    Hash,
+    Encodable,
+    Decodable,
+    HashStable_Generic
+)]
 pub enum Level {
     /// The `allow` level will not issue any message.
     Allow,
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 620d9f1c357..cae980cde61 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_errors::{Diag, MultiSpan};
 use rustc_hir::{HirId, ItemLocalId};
-use rustc_macros::HashStable;
+use rustc_macros::{Decodable, Encodable, HashStable};
 use rustc_session::Session;
 use rustc_session::lint::builtin::{self, FORBIDDEN_LINT_GROUPS};
 use rustc_session::lint::{FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId};
@@ -15,7 +15,7 @@ use tracing::instrument;
 use crate::ty::TyCtxt;
 
 /// How a lint level was set.
-#[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, HashStable, Debug)]
 pub enum LintLevelSource {
     /// Lint is at the default level as declared in rustc.
     Default,
@@ -173,7 +173,7 @@ impl TyCtxt<'_> {
 /// This struct represents a lint expectation and holds all required information
 /// to emit the `unfulfilled_lint_expectations` lint if it is unfulfilled after
 /// the `LateLintPass` has completed.
-#[derive(Clone, Debug, HashStable)]
+#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
 pub struct LintExpectation {
     /// The reason for this expectation that can optionally be added as part of
     /// the attribute. It will be displayed as part of the lint message.