Skip to content

Commit 537218a

Browse files
committed
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.
1 parent c0822ed commit 537218a

File tree

5 files changed

+85
-11
lines changed

5 files changed

+85
-11
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ use rustc_ast::CRATE_NODE_ID;
1515
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
1616
use rustc_data_structures::memmap::Mmap;
1717
use rustc_data_structures::temp_dir::MaybeTempDir;
18-
use rustc_errors::DiagCtxtHandle;
18+
use rustc_errors::{DiagCtxtHandle, LintDiagnostic};
1919
use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
2020
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
21-
use rustc_macros::Diagnostic;
21+
use rustc_macros::LintDiagnostic;
2222
use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
2323
use rustc_metadata::{find_native_static_library, walk_native_lib_search_dirs};
2424
use rustc_middle::bug;
25+
use rustc_middle::lint::lint_level;
2526
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
2627
use rustc_middle::middle::dependency_format::Linkage;
2728
use rustc_middle::middle::exported_symbols::SymbolExportKind;
@@ -30,6 +31,7 @@ use rustc_session::config::{
3031
OutputType, PrintKind, SplitDwarfKind, Strip,
3132
};
3233
use rustc_session::cstore::DllImport;
34+
use rustc_session::lint::builtin::LINKER_MESSAGES;
3335
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
3436
use rustc_session::search_paths::PathKind;
3537
use rustc_session::utils::NativeLibKind;
@@ -750,7 +752,7 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out
750752
}
751753
}
752754

753-
#[derive(Diagnostic)]
755+
#[derive(LintDiagnostic)]
754756
#[diag(codegen_ssa_linker_output)]
755757
/// Translating this is kind of useless. We don't pass translation flags to the linker, so we'd just
756758
/// end up with inconsistent languages within the same diagnostic.
@@ -1038,6 +1040,13 @@ fn link_natively(
10381040
sess.dcx().abort_if_errors();
10391041
}
10401042

1043+
let (level, src) = codegen_results.crate_info.lint_levels.linker_messages;
1044+
let lint = |msg| {
1045+
lint_level(sess, LINKER_MESSAGES, level, src, None, |diag| {
1046+
LinkerOutput { inner: msg }.decorate_lint(diag)
1047+
})
1048+
};
1049+
10411050
if !prog.stderr.is_empty() {
10421051
// We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present.
10431052
let stderr = escape_string(&prog.stderr);
@@ -1046,12 +1055,10 @@ fn link_natively(
10461055
.strip_prefix("warning: ")
10471056
.unwrap_or(&stderr)
10481057
.replace(": warning: ", ": ");
1049-
sess.dcx().emit_warn(LinkerOutput { inner: format!("linker stderr: {stderr}") });
1058+
lint(format!("linker stderr: {stderr}"));
10501059
}
10511060
if !prog.stdout.is_empty() && sess.opts.verbose {
1052-
sess.dcx().emit_warn(LinkerOutput {
1053-
inner: format!("linker stdout: {}", escape_string(&prog.stdout)),
1054-
});
1061+
lint(format!("linker stdout: {}", escape_string(&prog.stdout)))
10551062
}
10561063
}
10571064
Err(e) => {

compiler/rustc_codegen_ssa/src/lib.rs

+21
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,23 @@ use rustc_ast as ast;
2929
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
3030
use rustc_data_structures::sync::Lrc;
3131
use rustc_data_structures::unord::UnordMap;
32+
use rustc_hir::CRATE_HIR_ID;
3233
use rustc_hir::def_id::CrateNum;
3334
use rustc_macros::{Decodable, Encodable, HashStable};
3435
use rustc_middle::dep_graph::WorkProduct;
36+
use rustc_middle::lint::LintLevelSource;
3537
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
3638
use rustc_middle::middle::dependency_format::Dependencies;
3739
use rustc_middle::middle::exported_symbols::SymbolExportKind;
40+
use rustc_middle::ty::TyCtxt;
3841
use rustc_middle::util::Providers;
3942
use rustc_serialize::opaque::{FileEncoder, MemDecoder};
4043
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
4144
use rustc_session::Session;
4245
use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
4346
use rustc_session::cstore::{self, CrateSource};
47+
use rustc_session::lint::Level;
48+
use rustc_session::lint::builtin::LINKER_MESSAGES;
4449
use rustc_session::utils::NativeLibKind;
4550
use rustc_span::Symbol;
4651

@@ -303,3 +308,19 @@ impl CodegenResults {
303308
Ok((codegen_results, outputs))
304309
}
305310
}
311+
312+
/// A list of lint levels used in codegen.
313+
///
314+
/// When using `-Z link-only`, we don't have access to the tcx and must work
315+
/// solely from the `.rlink` file. `Lint`s are defined too early to be encodeable.
316+
/// Instead, encode exactly the information we need.
317+
#[derive(Copy, Clone, Debug, Encodable, Decodable)]
318+
pub struct CodegenLintLevels {
319+
linker_messages: (Level, LintLevelSource),
320+
}
321+
322+
impl CodegenLintLevels {
323+
pub fn from_tcx(tcx: TyCtxt<'_>) -> Self {
324+
Self { linker_messages: tcx.lint_level_at_node(LINKER_MESSAGES, CRATE_HIR_ID) }
325+
}
326+
}

compiler/rustc_lint_defs/src/builtin.rs

+34
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ declare_lint_pass! {
6060
LARGE_ASSIGNMENTS,
6161
LATE_BOUND_LIFETIME_ARGUMENTS,
6262
LEGACY_DERIVE_HELPERS,
63+
LINKER_MESSAGES,
6364
LONG_RUNNING_CONST_EVAL,
6465
LOSSY_PROVENANCE_CASTS,
6566
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
@@ -4085,6 +4086,39 @@ declare_lint! {
40854086
"call to foreign functions or function pointers with FFI-unwind ABI"
40864087
}
40874088

4089+
declare_lint! {
4090+
/// The `linker_messages` lint forwards warnings from the linker.
4091+
///
4092+
/// ### Example
4093+
///
4094+
/// ```rust,ignore (needs CLI args, platform-specific)
4095+
/// extern "C" {
4096+
/// fn foo();
4097+
/// }
4098+
/// fn main () { unsafe { foo(); } }
4099+
/// ```
4100+
///
4101+
/// On Linux, using `gcc -Wl,--warn-unresolved-symbols` as a linker, this will produce
4102+
///
4103+
/// ```text
4104+
/// warning: linker stderr: rust-lld: undefined symbol: foo
4105+
/// >>> referenced by rust_out.69edbd30df4ae57d-cgu.0
4106+
/// >>> rust_out.rust_out.69edbd30df4ae57d-cgu.0.rcgu.o:(rust_out::main::h3a90094b06757803)
4107+
/// |
4108+
/// = note: `#[warn(linker_messages)]` on by default
4109+
///
4110+
/// warning: 1 warning emitted
4111+
/// ```
4112+
///
4113+
/// ### Explanation
4114+
///
4115+
/// Linkers emit platform-specific and program-specific warnings that cannot be predicted in advance by the rust compiler.
4116+
/// They are forwarded by default, but can be disabled by adding `#![allow(linker_messages)]` at the crate root.
4117+
pub LINKER_MESSAGES,
4118+
Warn,
4119+
"warnings emitted at runtime by the target-specific linker program"
4120+
}
4121+
40884122
declare_lint! {
40894123
/// The `named_arguments_used_positionally` lint detects cases where named arguments are only
40904124
/// used positionally in format strings. This usage is valid but potentially very confusing.

compiler/rustc_lint_defs/src/lib.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,19 @@ impl<HCX: rustc_hir::HashStableContext> ToStableHashKey<HCX> for LintExpectation
161161
/// Setting for how to handle a lint.
162162
///
163163
/// See: <https://doc.rust-lang.org/rustc/lints/levels.html>
164-
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, HashStable_Generic)]
164+
#[derive(
165+
Clone,
166+
Copy,
167+
PartialEq,
168+
PartialOrd,
169+
Eq,
170+
Ord,
171+
Debug,
172+
Hash,
173+
Encodable,
174+
Decodable,
175+
HashStable_Generic
176+
)]
165177
pub enum Level {
166178
/// The `allow` level will not issue any message.
167179
Allow,

compiler/rustc_middle/src/lint.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxIndexMap;
44
use rustc_data_structures::sorted_map::SortedMap;
55
use rustc_errors::{Diag, MultiSpan};
66
use rustc_hir::{HirId, ItemLocalId};
7-
use rustc_macros::HashStable;
7+
use rustc_macros::{Decodable, Encodable, HashStable};
88
use rustc_session::Session;
99
use rustc_session::lint::builtin::{self, FORBIDDEN_LINT_GROUPS};
1010
use rustc_session::lint::{FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId};
@@ -15,7 +15,7 @@ use tracing::instrument;
1515
use crate::ty::TyCtxt;
1616

1717
/// How a lint level was set.
18-
#[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)]
18+
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, HashStable, Debug)]
1919
pub enum LintLevelSource {
2020
/// Lint is at the default level as declared in rustc.
2121
Default,
@@ -173,7 +173,7 @@ impl TyCtxt<'_> {
173173
/// This struct represents a lint expectation and holds all required information
174174
/// to emit the `unfulfilled_lint_expectations` lint if it is unfulfilled after
175175
/// the `LateLintPass` has completed.
176-
#[derive(Clone, Debug, HashStable)]
176+
#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
177177
pub struct LintExpectation {
178178
/// The reason for this expectation that can optionally be added as part of
179179
/// the attribute. It will be displayed as part of the lint message.

0 commit comments

Comments
 (0)