Skip to content

Commit b757663

Browse files
committed
don't ICE when emitting linker errors during -Z link-only
note that this still ICEs when passed `-Z link-only --error-format json` because i can't be bothered to fix it right now
1 parent cedd4ca commit b757663

File tree

5 files changed

+67
-22
lines changed

5 files changed

+67
-22
lines changed

Diff for: compiler/rustc_errors/src/json.rs

+30-17
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_error_messages::FluentArgs;
2121
use rustc_lint_defs::Applicability;
2222
use rustc_span::Span;
2323
use rustc_span::hygiene::ExpnData;
24-
use rustc_span::source_map::SourceMap;
24+
use rustc_span::source_map::{FilePathMapping, SourceMap};
2525
use serde::Serialize;
2626
use termcolor::{ColorSpec, WriteColor};
2727

@@ -45,7 +45,7 @@ pub struct JsonEmitter {
4545
#[setters(skip)]
4646
dst: IntoDynSyncSend<Box<dyn Write + Send>>,
4747
#[setters(skip)]
48-
sm: Lrc<SourceMap>,
48+
sm: Option<Lrc<SourceMap>>,
4949
fluent_bundle: Option<Lrc<FluentBundle>>,
5050
#[setters(skip)]
5151
fallback_bundle: LazyFallbackBundle,
@@ -65,7 +65,7 @@ pub struct JsonEmitter {
6565
impl JsonEmitter {
6666
pub fn new(
6767
dst: Box<dyn Write + Send>,
68-
sm: Lrc<SourceMap>,
68+
sm: Option<Lrc<SourceMap>>,
6969
fallback_bundle: LazyFallbackBundle,
7070
pretty: bool,
7171
json_rendered: HumanReadableErrorType,
@@ -171,7 +171,7 @@ impl Emitter for JsonEmitter {
171171
}
172172

173173
fn source_map(&self) -> Option<&SourceMap> {
174-
Some(&self.sm)
174+
self.sm.as_deref()
175175
}
176176

177177
fn should_show_explain(&self) -> bool {
@@ -371,7 +371,7 @@ impl Diagnostic {
371371
}
372372
HumanEmitter::new(dst, Lrc::clone(&je.fallback_bundle))
373373
.short_message(short)
374-
.sm(Some(Lrc::clone(&je.sm)))
374+
.sm(je.sm.clone())
375375
.fluent_bundle(je.fluent_bundle.clone())
376376
.diagnostic_width(je.diagnostic_width)
377377
.macro_backtrace(je.macro_backtrace)
@@ -458,23 +458,34 @@ impl DiagnosticSpan {
458458
mut backtrace: impl Iterator<Item = ExpnData>,
459459
je: &JsonEmitter,
460460
) -> DiagnosticSpan {
461-
let start = je.sm.lookup_char_pos(span.lo());
461+
let empty_source_map;
462+
let sm = match &je.sm {
463+
Some(s) => s,
464+
None => {
465+
span = rustc_span::DUMMY_SP;
466+
empty_source_map = Arc::new(SourceMap::new(FilePathMapping::empty()));
467+
empty_source_map
468+
.new_source_file(std::path::PathBuf::from("empty.rs").into(), String::new());
469+
&empty_source_map
470+
}
471+
};
472+
let start = sm.lookup_char_pos(span.lo());
462473
// If this goes from the start of a line to the end and the replacement
463474
// is an empty string, increase the length to include the newline so we don't
464475
// leave an empty line
465476
if start.col.0 == 0
466477
&& let Some((suggestion, _)) = suggestion
467478
&& suggestion.is_empty()
468-
&& let Ok(after) = je.sm.span_to_next_source(span)
479+
&& let Ok(after) = sm.span_to_next_source(span)
469480
&& after.starts_with('\n')
470481
{
471482
span = span.with_hi(span.hi() + rustc_span::BytePos(1));
472483
}
473-
let end = je.sm.lookup_char_pos(span.hi());
484+
let end = sm.lookup_char_pos(span.hi());
474485
let backtrace_step = backtrace.next().map(|bt| {
475486
let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je);
476487
let def_site_span = Self::from_span_full(
477-
je.sm.guess_head_span(bt.def_site),
488+
sm.guess_head_span(bt.def_site),
478489
false,
479490
None,
480491
None,
@@ -489,7 +500,7 @@ impl DiagnosticSpan {
489500
});
490501

491502
DiagnosticSpan {
492-
file_name: je.sm.filename_for_diagnostics(&start.file.name).to_string(),
503+
file_name: sm.filename_for_diagnostics(&start.file.name).to_string(),
493504
byte_start: start.file.original_relative_byte_pos(span.lo()).0,
494505
byte_end: start.file.original_relative_byte_pos(span.hi()).0,
495506
line_start: start.line,
@@ -559,19 +570,20 @@ impl DiagnosticSpanLine {
559570
/// `span` within the line.
560571
fn from_span(span: Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> {
561572
je.sm
562-
.span_to_lines(span)
563-
.map(|lines| {
573+
.as_ref()
574+
.and_then(|sm| {
575+
let lines = sm.span_to_lines(span).ok()?;
564576
// We can't get any lines if the source is unavailable.
565577
if !should_show_source_code(
566578
&je.ignored_directories_in_source_blocks,
567-
&je.sm,
579+
&sm,
568580
&lines.file,
569581
) {
570-
return vec![];
582+
return None;
571583
}
572584

573585
let sf = &*lines.file;
574-
lines
586+
let span_lines = lines
575587
.lines
576588
.iter()
577589
.map(|line| {
@@ -582,8 +594,9 @@ impl DiagnosticSpanLine {
582594
line.end_col.0 + 1,
583595
)
584596
})
585-
.collect()
597+
.collect();
598+
Some(span_lines)
586599
})
587-
.unwrap_or_else(|_| vec![])
600+
.unwrap_or_default()
588601
}
589602
}

Diff for: compiler/rustc_errors/src/json/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
4747
let output = Arc::new(Mutex::new(Vec::new()));
4848
let je = JsonEmitter::new(
4949
Box::new(Shared { data: output.clone() }),
50-
sm,
50+
Some(sm),
5151
fallback_bundle,
5252
true, // pretty
5353
HumanReadableErrorType::Short,

Diff for: compiler/rustc_session/src/session.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -895,13 +895,16 @@ fn default_emitter(
895895
}
896896
t => t,
897897
};
898+
899+
let source_map = if sopts.unstable_opts.link_only { None } else { Some(source_map) };
900+
898901
match sopts.error_format {
899902
config::ErrorOutputType::HumanReadable(kind, color_config) => {
900903
let short = kind.short();
901904

902905
if let HumanReadableErrorType::AnnotateSnippet = kind {
903906
let emitter = AnnotateSnippetEmitter::new(
904-
Some(source_map),
907+
source_map,
905908
bundle,
906909
fallback_bundle,
907910
short,
@@ -911,7 +914,7 @@ fn default_emitter(
911914
} else {
912915
let emitter = HumanEmitter::new(stderr_destination(color_config), fallback_bundle)
913916
.fluent_bundle(bundle)
914-
.sm(Some(source_map))
917+
.sm(source_map)
915918
.short_message(short)
916919
.teach(sopts.unstable_opts.teach)
917920
.diagnostic_width(sopts.diagnostic_width)
@@ -1442,7 +1445,7 @@ fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> {
14421445
config::ErrorOutputType::Json { pretty, json_rendered, color_config } => {
14431446
Box::new(JsonEmitter::new(
14441447
Box::new(io::BufWriter::new(io::stderr())),
1445-
Lrc::new(SourceMap::new(FilePathMapping::empty())),
1448+
Some(Lrc::new(SourceMap::new(FilePathMapping::empty()))),
14461449
fallback_bundle,
14471450
pretty,
14481451
json_rendered,

Diff for: src/librustdoc/core.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ pub(crate) fn new_dcx(
178178
Box::new(
179179
JsonEmitter::new(
180180
Box::new(io::BufWriter::new(io::stderr())),
181-
source_map,
181+
Some(source_map),
182182
fallback_bundle,
183183
pretty,
184184
json_rendered,

Diff for: tests/run-make/linker-warning/rmake.rs

+29
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,33 @@ fn main() {
4444
.assert_stderr_contains("object files omitted")
4545
.assert_stderr_contains_regex(r"\{")
4646
.assert_stderr_not_contains_regex(r"lib(/|\\\\)libstd");
47+
48+
// Make sure we show linker warnings even across `-Z no-link`
49+
rustc()
50+
.arg("-Zno-link")
51+
.input("-")
52+
.stdin_buf("#![deny(linker_messages)] \n fn main() {}")
53+
.run()
54+
.assert_stderr_equals("");
55+
rustc()
56+
.arg("-Zlink-only")
57+
.arg("rust_out.rlink")
58+
.linker("./fake-linker")
59+
.link_arg("run_make_warn")
60+
.run_fail()
61+
// NOTE: the error message here is quite bad (we don't have a source
62+
// span, but still try to print the lint source). But `-Z link-only` is
63+
// unstable and this still shows the linker warning itself so this is
64+
// probably good enough.
65+
.assert_stderr_contains("linker stderr: bar");
66+
67+
// Same thing, but with json output.
68+
rustc()
69+
.error_format("json")
70+
.arg("-Zlink-only")
71+
.arg("rust_out.rlink")
72+
.linker("./fake-linker")
73+
.link_arg("run_make_warn")
74+
.run_fail()
75+
.assert_stderr_contains(r#""$message_type":"diagnostic""#);
4776
}

0 commit comments

Comments
 (0)