Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 9e233a0

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 b1dfee8 commit 9e233a0

File tree

10 files changed

+173
-64
lines changed

10 files changed

+173
-64
lines changed

compiler/rustc_codegen_llvm/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use rustc_codegen_ssa::back::write::{
3434
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
3535
};
3636
use rustc_codegen_ssa::traits::*;
37-
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
37+
use rustc_codegen_ssa::{CodegenLintLevels, CodegenResults, CompiledModule, ModuleCodegen};
3838
use rustc_data_structures::fx::FxIndexMap;
3939
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError};
4040
use rustc_metadata::EncodedMetadata;
@@ -374,6 +374,7 @@ impl CodegenBackend for LlvmCodegenBackend {
374374
&self,
375375
sess: &Session,
376376
codegen_results: CodegenResults,
377+
lint_levels: CodegenLintLevels,
377378
outputs: &OutputFilenames,
378379
) -> Result<(), ErrorGuaranteed> {
379380
use rustc_codegen_ssa::back::link::link_binary;
@@ -382,7 +383,7 @@ impl CodegenBackend for LlvmCodegenBackend {
382383

383384
// Run the linker on any artifacts that resulted from the LLVM run.
384385
// This should produce either a finished executable or library.
385-
link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, outputs)
386+
link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, lint_levels, outputs)
386387
}
387388
}
388389

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 18 additions & 8 deletions
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, ErrorGuaranteed, FatalError};
18+
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError, 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;
@@ -53,7 +55,7 @@ use super::metadata::{MetadataPosition, create_wrapper_file};
5355
use super::rpath::{self, RPathConfig};
5456
use super::{apple, versioned_llvm_target};
5557
use crate::{
56-
CodegenResults, CompiledModule, CrateInfo, NativeLib, common, errors,
58+
CodegenLintLevels, CodegenResults, CompiledModule, CrateInfo, NativeLib, common, errors,
5759
looks_like_rust_object_file,
5860
};
5961

@@ -71,6 +73,7 @@ pub fn link_binary(
7173
sess: &Session,
7274
archive_builder_builder: &dyn ArchiveBuilderBuilder,
7375
codegen_results: CodegenResults,
76+
lint_levels: CodegenLintLevels,
7477
outputs: &OutputFilenames,
7578
) -> Result<(), ErrorGuaranteed> {
7679
let _timer = sess.timer("link_binary");
@@ -139,6 +142,7 @@ pub fn link_binary(
139142
crate_type,
140143
&out_filename,
141144
&codegen_results,
145+
lint_levels,
142146
path.as_ref(),
143147
)?;
144148
}
@@ -763,7 +767,7 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out
763767
}
764768
}
765769

766-
#[derive(Diagnostic)]
770+
#[derive(LintDiagnostic)]
767771
#[diag(codegen_ssa_linker_output)]
768772
/// Translating this is kind of useless. We don't pass translation flags to the linker, so we'd just
769773
/// end up with inconsistent languages within the same diagnostic.
@@ -781,6 +785,7 @@ fn link_natively(
781785
crate_type: CrateType,
782786
out_filename: &Path,
783787
codegen_results: &CodegenResults,
788+
lint_levels: CodegenLintLevels,
784789
tmpdir: &Path,
785790
) -> Result<(), ErrorGuaranteed> {
786791
info!("preparing {:?} to {:?}", crate_type, out_filename);
@@ -1055,6 +1060,13 @@ fn link_natively(
10551060
sess.dcx().abort_if_errors();
10561061
}
10571062

1063+
let (level, src) = lint_levels.linker_messages;
1064+
let lint = |msg| {
1065+
lint_level(sess, LINKER_MESSAGES, level, src, None, |diag| {
1066+
LinkerOutput { inner: msg }.decorate_lint(diag)
1067+
})
1068+
};
1069+
10581070
if !prog.stderr.is_empty() {
10591071
// We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present.
10601072
let stderr = escape_string(&prog.stderr);
@@ -1063,12 +1075,10 @@ fn link_natively(
10631075
.strip_prefix("warning: ")
10641076
.unwrap_or(&stderr)
10651077
.replace(": warning: ", ": ");
1066-
sess.dcx().emit_warn(LinkerOutput { inner: format!("linker stderr: {stderr}") });
1078+
lint(format!("linker stderr: {stderr}"));
10671079
}
10681080
if !prog.stdout.is_empty() && sess.opts.verbose {
1069-
sess.dcx().emit_warn(LinkerOutput {
1070-
inner: format!("linker stdout: {}", escape_string(&prog.stdout)),
1071-
});
1081+
lint(format!("linker stdout: {}", escape_string(&prog.stdout)))
10721082
}
10731083
}
10741084
Err(e) => {

compiler/rustc_codegen_ssa/src/lib.rs

Lines changed: 26 additions & 2 deletions
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::Symbol;
4651

@@ -251,6 +256,7 @@ impl CodegenResults {
251256
sess: &Session,
252257
rlink_file: &Path,
253258
codegen_results: &CodegenResults,
259+
lint_levels: CodegenLintLevels,
254260
outputs: &OutputFilenames,
255261
) -> Result<usize, io::Error> {
256262
let mut encoder = FileEncoder::new(rlink_file)?;
@@ -260,14 +266,15 @@ impl CodegenResults {
260266
encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes());
261267
encoder.emit_str(sess.cfg_version);
262268
Encodable::encode(codegen_results, &mut encoder);
269+
Encodable::encode(&lint_levels, &mut encoder);
263270
Encodable::encode(outputs, &mut encoder);
264271
encoder.finish().map_err(|(_path, err)| err)
265272
}
266273

267274
pub fn deserialize_rlink(
268275
sess: &Session,
269276
data: Vec<u8>,
270-
) -> Result<(Self, OutputFilenames), CodegenErrors> {
277+
) -> Result<(Self, CodegenLintLevels, OutputFilenames), CodegenErrors> {
271278
// The Decodable machinery is not used here because it panics if the input data is invalid
272279
// and because its internal representation may change.
273280
if !data.starts_with(RLINK_MAGIC) {
@@ -298,7 +305,24 @@ impl CodegenResults {
298305
}
299306

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

compiler/rustc_codegen_ssa/src/traits/backend.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use super::write::WriteBackendMethods;
1919
use crate::back::archive::ArArchiveBuilderBuilder;
2020
use crate::back::link::link_binary;
2121
use crate::back::write::TargetMachineFactoryFn;
22-
use crate::{CodegenResults, ModuleCodegen};
22+
use crate::{CodegenLintLevels, CodegenResults, ModuleCodegen};
2323

2424
pub trait BackendTypes {
2525
type Value: CodegenObject;
@@ -88,9 +88,10 @@ pub trait CodegenBackend {
8888
&self,
8989
sess: &Session,
9090
codegen_results: CodegenResults,
91+
lint_levels: CodegenLintLevels,
9192
outputs: &OutputFilenames,
9293
) -> Result<(), ErrorGuaranteed> {
93-
link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, outputs)
94+
link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, lint_levels, outputs)
9495
}
9596

9697
/// Returns `true` if this backend can be safely called from multiple threads.

compiler/rustc_driver_impl/src/lib.rs

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -643,27 +643,34 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
643643
let rlink_data = fs::read(file).unwrap_or_else(|err| {
644644
dcx.emit_fatal(RlinkUnableToRead { err });
645645
});
646-
let (codegen_results, outputs) = match CodegenResults::deserialize_rlink(sess, rlink_data) {
647-
Ok((codegen, outputs)) => (codegen, outputs),
648-
Err(err) => {
649-
match err {
650-
CodegenErrors::WrongFileType => dcx.emit_fatal(RLinkWrongFileType),
651-
CodegenErrors::EmptyVersionNumber => dcx.emit_fatal(RLinkEmptyVersionNumber),
652-
CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => dcx
653-
.emit_fatal(RLinkEncodingVersionMismatch { version_array, rlink_version }),
654-
CodegenErrors::RustcVersionMismatch { rustc_version } => {
655-
dcx.emit_fatal(RLinkRustcVersionMismatch {
656-
rustc_version,
657-
current_version: sess.cfg_version,
658-
})
659-
}
660-
CodegenErrors::CorruptFile => {
661-
dcx.emit_fatal(RlinkCorruptFile { file });
662-
}
663-
};
664-
}
665-
};
666-
if compiler.codegen_backend.link(sess, codegen_results, &outputs).is_err() {
646+
let (codegen_results, lint_levels, outputs) =
647+
match CodegenResults::deserialize_rlink(sess, rlink_data) {
648+
Ok((codegen, lints, outputs)) => (codegen, lints, outputs),
649+
Err(err) => {
650+
match err {
651+
CodegenErrors::WrongFileType => dcx.emit_fatal(RLinkWrongFileType),
652+
CodegenErrors::EmptyVersionNumber => {
653+
dcx.emit_fatal(RLinkEmptyVersionNumber)
654+
}
655+
CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => {
656+
dcx.emit_fatal(RLinkEncodingVersionMismatch {
657+
version_array,
658+
rlink_version,
659+
})
660+
}
661+
CodegenErrors::RustcVersionMismatch { rustc_version } => {
662+
dcx.emit_fatal(RLinkRustcVersionMismatch {
663+
rustc_version,
664+
current_version: sess.cfg_version,
665+
})
666+
}
667+
CodegenErrors::CorruptFile => {
668+
dcx.emit_fatal(RlinkCorruptFile { file });
669+
}
670+
};
671+
}
672+
};
673+
if compiler.codegen_backend.link(sess, codegen_results, lint_levels, &outputs).is_err() {
667674
FatalError.raise();
668675
}
669676
} else {

compiler/rustc_interface/src/queries.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::cell::{RefCell, RefMut};
33
use std::sync::Arc;
44

55
use rustc_ast as ast;
6-
use rustc_codegen_ssa::CodegenResults;
76
use rustc_codegen_ssa::traits::CodegenBackend;
7+
use rustc_codegen_ssa::{CodegenLintLevels, CodegenResults};
88
use rustc_data_structures::steal::Steal;
99
use rustc_data_structures::svh::Svh;
1010
use rustc_data_structures::sync::{OnceLock, WorkerLocal};
@@ -117,6 +117,7 @@ impl<'tcx> Queries<'tcx> {
117117
pub struct Linker {
118118
dep_graph: DepGraph,
119119
output_filenames: Arc<OutputFilenames>,
120+
lint_levels: CodegenLintLevels,
120121
// Only present when incr. comp. is enabled.
121122
crate_hash: Option<Svh>,
122123
ongoing_codegen: Box<dyn Any>,
@@ -144,6 +145,7 @@ impl Linker {
144145
Ok(Linker {
145146
dep_graph: tcx.dep_graph.clone(),
146147
output_filenames: Arc::clone(tcx.output_filenames(())),
148+
lint_levels: CodegenLintLevels::from_tcx(tcx),
147149
crate_hash: if tcx.needs_crate_hash() {
148150
Some(tcx.crate_hash(LOCAL_CRATE))
149151
} else {
@@ -187,6 +189,7 @@ impl Linker {
187189
sess,
188190
&rlink_file,
189191
&codegen_results,
192+
self.lint_levels,
190193
&*self.output_filenames,
191194
)
192195
.map_err(|error| {
@@ -196,7 +199,7 @@ impl Linker {
196199
}
197200

198201
let _timer = sess.prof.verbose_generic_activity("link_crate");
199-
codegen_backend.link(sess, codegen_results, &self.output_filenames)
202+
codegen_backend.link(sess, codegen_results, self.lint_levels, &self.output_filenames)
200203
}
201204
}
202205

compiler/rustc_lint/src/levels.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,17 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> {
130130
!has_future_breakage && !lint.eval_always
131131
})
132132
.filter_map(|lint| {
133-
let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID);
134-
if matches!(lint_level, (Level::Allow, ..))
135-
|| (matches!(lint_level, (.., LintLevelSource::Default)))
136-
&& lint.default_level(tcx.sess.edition()) == Level::Allow
137-
{
138-
Some(LintId::of(lint))
133+
if !lint.eval_always {
134+
let lint_level =
135+
map.lint_level_id_at_node(Some(tcx), tcx.sess, LintId::of(lint), CRATE_HIR_ID);
136+
if matches!(lint_level, (Level::Allow, ..))
137+
|| (matches!(lint_level, (.., LintLevelSource::Default)))
138+
&& lint.default_level(tcx.sess.edition()) == Level::Allow
139+
{
140+
Some(LintId::of(lint))
141+
} else {
142+
None
143+
}
139144
} else {
140145
None
141146
}
@@ -248,8 +253,8 @@ impl LintLevelsProvider for LintLevelQueryMap<'_> {
248253
fn insert(&mut self, id: LintId, lvl: LevelAndSource) {
249254
self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, lvl);
250255
}
251-
fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource {
252-
self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur)
256+
fn get_lint_level(&self, lint: &'static Lint, sess: &Session) -> LevelAndSource {
257+
self.specs.lint_level_id_at_node(Some(self.tcx), sess, LintId::of(lint), self.cur)
253258
}
254259
fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation) {
255260
self.specs.expectations.push((id, expectation))

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 34 additions & 0 deletions
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,
@@ -4080,6 +4081,39 @@ declare_lint! {
40804081
"call to foreign functions or function pointers with FFI-unwind ABI"
40814082
}
40824083

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

0 commit comments

Comments
 (0)