Skip to content

Commit 5f6d46f

Browse files
committed
Auto merge of rust-lang#119286 - jyn514:linker-output, r=bjorn3
show linker output even if the linker succeeds - show stderr by default - show stdout if `--verbose` is passed - remove both from RUSTC_LOG - hide the linker cli args unless `--verbose` is passed fixes rust-lang#83436. fixes rust-lang#38206. fixes rust-lang#109979. helps with rust-lang#46998. cc https://rust-lang.zulipchat.com/#narrow/stream/233931-t-compiler.2Fmajor-changes/topic/uplift.20some.20-Zverbose.20calls.20and.20rename.20to.E2.80.A6.20compiler-team.23706/near/408986134 this is based on rust-lang#119129 for convenience so i didn't have to duplicate the changes around saving `--verbose` in rust-lang@cb6d033#diff-7a49efa20548d6806dbe1c66dd4dc445fda18fcbbf1709520cadecc4841aae12 r? `@bjorn3`
2 parents 8d6b88b + 56b8c94 commit 5f6d46f

File tree

19 files changed

+284
-157
lines changed

19 files changed

+284
-157
lines changed

compiler/rustc_codegen_ssa/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ codegen_ssa_linker_file_stem = couldn't extract file stem from specified linker
172172
codegen_ssa_linker_not_found = linker `{$linker_path}` not found
173173
.note = {$error}
174174
175+
codegen_ssa_linker_output = {$inner}
176+
175177
codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker
176178
177179
codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}

compiler/rustc_codegen_ssa/src/back/link.rs

+26-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
1818
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError};
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;
2122
use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME};
2223
use rustc_metadata::{find_native_static_library, walk_native_lib_search_dirs};
2324
use rustc_middle::bug;
@@ -750,6 +751,14 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out
750751
}
751752
}
752753

754+
#[derive(Diagnostic)]
755+
#[diag(codegen_ssa_linker_output)]
756+
/// Translating this is kind of useless. We don't pass translation flags to the linker, so we'd just
757+
/// end up with inconsistent languages within the same diagnostic.
758+
struct LinkerOutput {
759+
inner: String,
760+
}
761+
753762
/// Create a dynamic library or executable.
754763
///
755764
/// This will invoke the system linker/cc to create the resulting file. This links to all upstream
@@ -976,12 +985,12 @@ fn link_natively(
976985
let mut output = prog.stderr.clone();
977986
output.extend_from_slice(&prog.stdout);
978987
let escaped_output = escape_linker_output(&output, flavor);
979-
// FIXME: Add UI tests for this error.
980988
let err = errors::LinkingFailed {
981989
linker_path: &linker_path,
982990
exit_status: prog.status,
983991
command: &cmd,
984992
escaped_output,
993+
verbose: sess.opts.verbose,
985994
};
986995
sess.dcx().emit_err(err);
987996
// If MSVC's `link.exe` was expected but the return code
@@ -1022,8 +1031,22 @@ fn link_natively(
10221031

10231032
sess.dcx().abort_if_errors();
10241033
}
1025-
info!("linker stderr:\n{}", escape_string(&prog.stderr));
1026-
info!("linker stdout:\n{}", escape_string(&prog.stdout));
1034+
1035+
if !prog.stderr.is_empty() {
1036+
// We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present.
1037+
let stderr = escape_string(&prog.stderr);
1038+
debug!("original stderr: {stderr}");
1039+
let stderr = stderr
1040+
.strip_prefix("warning: ")
1041+
.unwrap_or(&stderr)
1042+
.replace(": warning: ", ": ");
1043+
sess.dcx().emit_warn(LinkerOutput { inner: format!("linker stderr: {stderr}") });
1044+
}
1045+
if !prog.stdout.is_empty() && sess.opts.verbose {
1046+
sess.dcx().emit_warn(LinkerOutput {
1047+
inner: format!("linker stdout: {}", escape_string(&prog.stdout)),
1048+
});
1049+
}
10271050
}
10281051
Err(e) => {
10291052
let linker_not_found = e.kind() == io::ErrorKind::NotFound;

compiler/rustc_codegen_ssa/src/errors.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ pub struct LinkingFailed<'a> {
348348
pub exit_status: ExitStatus,
349349
pub command: &'a Command,
350350
pub escaped_output: String,
351+
pub verbose: bool,
351352
}
352353

353354
impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
@@ -358,7 +359,13 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
358359

359360
let contains_undefined_ref = self.escaped_output.contains("undefined reference to");
360361

361-
diag.note(format!("{:?}", self.command)).note(self.escaped_output);
362+
if self.verbose {
363+
diag.note(format!("{:?}", self.command));
364+
} else {
365+
diag.note("use `--verbose` to show all linker arguments");
366+
}
367+
368+
diag.note(self.escaped_output);
362369

363370
// Trying to match an error from OS linkers
364371
// which by now we have no way to translate.

compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,10 @@ impl DiagnosticDeriveVariantBuilder {
253253
let mut field_binding = binding_info.binding.clone();
254254
field_binding.set_span(field.ty.span());
255255

256-
let ident = field.ident.as_ref().unwrap();
256+
let Some(ident) = field.ident.as_ref() else {
257+
span_err(field.span().unwrap(), "tuple structs are not supported").emit();
258+
return TokenStream::new();
259+
};
257260
let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
258261

259262
quote! {

compiler/rustc_macros/src/diagnostics/error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ fn path_to_string(path: &syn::Path) -> String {
5656
/// Returns an error diagnostic on span `span` with msg `msg`.
5757
#[must_use]
5858
pub(crate) fn span_err<T: Into<String>>(span: impl MultiSpan, msg: T) -> Diagnostic {
59-
Diagnostic::spanned(span, Level::Error, msg)
59+
Diagnostic::spanned(span, Level::Error, format!("derive(Diagnostic): {}", msg.into()))
6060
}
6161

6262
/// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration

compiler/rustc_macros/src/diagnostics/utils.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ impl<T> SetOnce<T> for SpannedOption<T> {
243243
*self = Some((value, span));
244244
}
245245
Some((_, prev_span)) => {
246-
span_err(span, "specified multiple times")
246+
span_err(span, "attribute specified multiple times")
247247
.span_note(*prev_span, "previously specified here")
248248
.emit();
249249
}

src/etc/cat-and-grep.sh

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ while getopts ':vieh' OPTION; do
3333
case "$OPTION" in
3434
v)
3535
INVERT=1
36-
ERROR_MSG='should not be found'
3736
;;
3837
i)
3938
GREPFLAGS="i$GREPFLAGS"

src/tools/compiletest/src/runtest.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1778,6 +1778,10 @@ impl<'test> TestCx<'test> {
17781778
self.config.target.contains("vxworks") && !self.is_vxworks_pure_static()
17791779
}
17801780

1781+
fn has_aux_dir(&self) -> bool {
1782+
!self.props.aux_builds.is_empty() || !self.props.aux_crates.is_empty()
1783+
}
1784+
17811785
fn aux_output_dir(&self) -> PathBuf {
17821786
let aux_dir = self.aux_output_dir_name();
17831787

@@ -2324,7 +2328,11 @@ impl<'test> TestCx<'test> {
23242328
}
23252329

23262330
if let LinkToAux::Yes = link_to_aux {
2327-
rustc.arg("-L").arg(self.aux_output_dir_name());
2331+
// if we pass an `-L` argument to a directory that doesn't exist,
2332+
// macOS ld emits warnings which disrupt the .stderr files
2333+
if self.has_aux_dir() {
2334+
rustc.arg("-L").arg(self.aux_output_dir_name());
2335+
}
23282336
}
23292337

23302338
rustc.args(&self.props.compile_flags);

src/tools/run-make-support/src/external_deps/rustc.rs

+6
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,12 @@ impl Rustc {
319319
self
320320
}
321321

322+
/// Pass the `--verbose` flag.
323+
pub fn verbose(&mut self) -> &mut Self {
324+
self.cmd.arg("--verbose");
325+
self
326+
}
327+
322328
/// `EXTRARSCXXFLAGS`
323329
pub fn extra_rs_cxx_flags(&mut self) -> &mut Self {
324330
// Adapted from tools.mk (trimmed):

tests/run-make/link-args-order/rmake.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@ fn main() {
1515
.link_args("b c")
1616
.link_args("d e")
1717
.link_arg("f")
18+
.arg("--print=link-args")
1819
.run_fail()
19-
.assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#);
20+
.assert_stdout_contains(r#""a" "b" "c" "d" "e" "f""#);
2021
rustc()
2122
.input("empty.rs")
2223
.linker_flavor(linker)
2324
.arg("-Zpre-link-arg=a")
2425
.arg("-Zpre-link-args=b c")
2526
.arg("-Zpre-link-args=d e")
2627
.arg("-Zpre-link-arg=f")
28+
.arg("--print=link-args")
2729
.run_fail()
28-
.assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#);
30+
.assert_stdout_contains(r#""a" "b" "c" "d" "e" "f""#);
2931
}

tests/run-make/link-dedup/rmake.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ fn main() {
1414
rustc().input("depb.rs").run();
1515
rustc().input("depc.rs").run();
1616

17-
let output = rustc().input("empty.rs").cfg("bar").run_fail();
18-
output.assert_stderr_contains(needle_from_libs(&["testa", "testb", "testa"]));
17+
let output = rustc().input("empty.rs").cfg("bar").arg("--print=link-args").run_fail();
18+
output.assert_stdout_contains(needle_from_libs(&["testa", "testb", "testa"]));
1919

20-
let output = rustc().input("empty.rs").run_fail();
21-
output.assert_stderr_contains(needle_from_libs(&["testa"]));
22-
output.assert_stderr_not_contains(needle_from_libs(&["testb"]));
23-
output.assert_stderr_not_contains(needle_from_libs(&["testa", "testa", "testa"]));
20+
let output = rustc().input("empty.rs").arg("--print=link-args").run_fail();
21+
output.assert_stdout_contains(needle_from_libs(&["testa"]));
22+
output.assert_stdout_not_contains(needle_from_libs(&["testb"]));
23+
output.assert_stdout_not_contains(needle_from_libs(&["testa", "testa", "testa"]));
2424
// Adjacent identical native libraries are no longer deduplicated if
2525
// they come from different crates (https://github.com/rust-lang/rust/pull/103311)
2626
// so the following will fail:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
fn main() {
2+
for arg in std::env::args() {
3+
match &*arg {
4+
"run_make_info" => println!("foo"),
5+
"run_make_warn" => eprintln!("warning: bar"),
6+
"run_make_error" => {
7+
eprintln!("error: baz");
8+
std::process::exit(1);
9+
}
10+
_ => (),
11+
}
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/bin/sh
2+
3+
code=0
4+
while ! [ $# = 0 ]; do
5+
case "$1" in
6+
run_make_info) echo "foo"
7+
;;
8+
run_make_warn) echo "warning: bar" >&2
9+
;;
10+
run_make_error) echo "error: baz" >&2; code=1
11+
;;
12+
*) ;; # rustc passes lots of args we don't care about
13+
esac
14+
shift
15+
done
16+
17+
exit $code

tests/run-make/linker-warning/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fn main() {}
+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use std::path::Path;
2+
3+
use run_make_support::rfs::remove_file;
4+
use run_make_support::{rustc, Rustc};
5+
6+
fn run_rustc() -> Rustc {
7+
let mut rustc = rustc();
8+
rustc.arg("main.rs").output("main").linker("./fake-linker");
9+
rustc
10+
}
11+
12+
fn main() {
13+
// first, compile our linker
14+
rustc().arg("fake-linker.rs").output("fake-linker").run();
15+
16+
// Run rustc with our fake linker, and make sure it shows warnings
17+
let warnings = run_rustc().link_arg("run_make_warn").run();
18+
warnings.assert_stderr_contains("warning: linker stderr: bar");
19+
20+
// Make sure it shows stdout, but only when --verbose is passed
21+
run_rustc()
22+
.link_arg("run_make_info")
23+
.verbose()
24+
.run()
25+
.assert_stderr_contains("warning: linker stdout: foo");
26+
run_rustc()
27+
.link_arg("run_make_info")
28+
.run()
29+
.assert_stderr_not_contains("warning: linker stdout: foo");
30+
31+
// Make sure we short-circuit this new path if the linker exits with an error
32+
// (so the diagnostic is less verbose)
33+
run_rustc().link_arg("run_make_error").run_fail().assert_stderr_contains("note: error: baz");
34+
35+
// Make sure we don't show the linker args unless `--verbose` is passed
36+
run_rustc()
37+
.link_arg("run_make_error")
38+
.verbose()
39+
.run_fail()
40+
.assert_stderr_contains_regex("fake-linker.*run_make_error");
41+
run_rustc()
42+
.link_arg("run_make_error")
43+
.run_fail()
44+
.assert_stderr_not_contains_regex("fake-linker.*run_make_error");
45+
}

tests/run-make/rust-lld/rmake.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ fn main() {
1414
// Opt-in to lld and the self-contained linker, to link with rust-lld. We'll check that by
1515
// asking the linker to display its version number with a link-arg.
1616
let output = rustc()
17-
.env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info")
1817
.arg("-Zlinker-features=+lld")
1918
.arg("-Clink-self-contained=+linker")
2019
.arg("-Zunstable-options")
20+
.arg("--verbose")
2121
.link_arg(linker_version_flag)
2222
.input("main.rs")
2323
.run();
@@ -29,8 +29,8 @@ fn main() {
2929

3030
// It should not be used when we explicitly opt-out of lld.
3131
let output = rustc()
32-
.env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info")
3332
.link_arg(linker_version_flag)
33+
.arg("--verbose")
3434
.arg("-Zlinker-features=-lld")
3535
.input("main.rs")
3636
.run();
@@ -43,8 +43,8 @@ fn main() {
4343
// While we're here, also check that the last linker feature flag "wins" when passed multiple
4444
// times to rustc.
4545
let output = rustc()
46-
.env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info")
4746
.link_arg(linker_version_flag)
47+
.arg("--verbose")
4848
.arg("-Clink-self-contained=+linker")
4949
.arg("-Zunstable-options")
5050
.arg("-Zlinker-features=-lld")
@@ -60,6 +60,7 @@ fn main() {
6060
}
6161

6262
fn find_lld_version_in_logs(stderr: String) -> bool {
63-
let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
63+
let lld_version_re =
64+
Regex::new(r"^warning: linker stdout: LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
6465
stderr.lines().any(|line| lld_version_re.is_match(line.trim()))
6566
}

0 commit comments

Comments
 (0)