1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 pub use self::Level
::*;
12 pub use self::RenderSpan
::*;
13 pub use self::ColorConfig
::*;
14 use self::Destination
::*;
16 use codemap
::{self, COMMAND_LINE_SP, COMMAND_LINE_EXPN, Pos, Span}
;
19 use std
::cell
::{RefCell, Cell}
;
20 use std
::{cmp, error, fmt}
;
21 use std
::io
::prelude
::*;
23 use term
::{self, WriterWrapper}
;
26 /// maximum number of lines we will print for each error; arbitrary.
27 const MAX_LINES
: usize = 6;
31 /// A FullSpan renders with both with an initial line for the
32 /// message, prefixed by file:linenum, followed by a summary of
33 /// the source code covered by the span.
36 /// Similar to a FullSpan, but the cited position is the end of
37 /// the span, instead of the start. Used, at least, for telling
38 /// compiletest/runtest to look at the last line of the span
39 /// (since `end_highlight_lines` displays an arrow to the end
43 /// A suggestion renders with both with an initial line for the
44 /// message, prefixed by file:linenum, followed by a summary
45 /// of hypothetical source code, where the `String` is spliced
46 /// into the lines in place of the code covered by the span.
47 Suggestion(Span
, String
),
49 /// A FileLine renders with just a line for the message prefixed
55 fn span(&self) -> Span
{
66 #[derive(Clone, Copy)]
67 pub enum ColorConfig
{
74 fn emit(&mut self, cmsp
: Option
<(&codemap
::CodeMap
, Span
)>,
75 msg
: &str, code
: Option
<&str>, lvl
: Level
);
76 fn custom_emit(&mut self, cm
: &codemap
::CodeMap
,
77 sp
: RenderSpan
, msg
: &str, lvl
: Level
);
80 /// Used as a return value to signify a fatal error occurred. (It is also
81 /// used as the argument to panic at the moment, but that will eventually
83 #[derive(Copy, Clone, Debug)]
85 pub struct FatalError
;
87 impl fmt
::Display
for FatalError
{
88 fn fmt(&self, f
: &mut fmt
::Formatter
) -> Result
<(), fmt
::Error
> {
89 write
!(f
, "parser fatal error")
93 impl error
::Error
for FatalError
{
94 fn description(&self) -> &str {
95 "The parser has encountered a fatal error"
99 /// Signifies that the compiler died with an explicit call to `.bug`
100 /// or `.span_bug` rather than a failed assertion, etc.
101 #[derive(Copy, Clone, Debug)]
102 pub struct ExplicitBug
;
104 impl fmt
::Display
for ExplicitBug
{
105 fn fmt(&self, f
: &mut fmt
::Formatter
) -> Result
<(), fmt
::Error
> {
106 write
!(f
, "parser internal bug")
110 impl error
::Error
for ExplicitBug
{
111 fn description(&self) -> &str {
112 "The parser has encountered an internal bug"
116 /// A span-handler is like a handler but also
117 /// accepts span information for source-location
119 pub struct SpanHandler
{
120 pub handler
: Handler
,
121 pub cm
: codemap
::CodeMap
,
125 pub fn new(handler
: Handler
, cm
: codemap
::CodeMap
) -> SpanHandler
{
131 pub fn span_fatal(&self, sp
: Span
, msg
: &str) -> FatalError
{
132 self.handler
.emit(Some((&self.cm
, sp
)), msg
, Fatal
);
135 pub fn span_fatal_with_code(&self, sp
: Span
, msg
: &str, code
: &str) -> FatalError
{
136 self.handler
.emit_with_code(Some((&self.cm
, sp
)), msg
, code
, Fatal
);
139 pub fn span_err(&self, sp
: Span
, msg
: &str) {
140 self.handler
.emit(Some((&self.cm
, sp
)), msg
, Error
);
141 self.handler
.bump_err_count();
143 pub fn span_err_with_code(&self, sp
: Span
, msg
: &str, code
: &str) {
144 self.handler
.emit_with_code(Some((&self.cm
, sp
)), msg
, code
, Error
);
145 self.handler
.bump_err_count();
147 pub fn span_warn(&self, sp
: Span
, msg
: &str) {
148 self.handler
.emit(Some((&self.cm
, sp
)), msg
, Warning
);
150 pub fn span_warn_with_code(&self, sp
: Span
, msg
: &str, code
: &str) {
151 self.handler
.emit_with_code(Some((&self.cm
, sp
)), msg
, code
, Warning
);
153 pub fn span_note(&self, sp
: Span
, msg
: &str) {
154 self.handler
.emit(Some((&self.cm
, sp
)), msg
, Note
);
156 pub fn span_end_note(&self, sp
: Span
, msg
: &str) {
157 self.handler
.custom_emit(&self.cm
, EndSpan(sp
), msg
, Note
);
159 pub fn span_help(&self, sp
: Span
, msg
: &str) {
160 self.handler
.emit(Some((&self.cm
, sp
)), msg
, Help
);
162 /// Prints out a message with a suggested edit of the code.
164 /// See `diagnostic::RenderSpan::Suggestion` for more information.
165 pub fn span_suggestion(&self, sp
: Span
, msg
: &str, suggestion
: String
) {
166 self.handler
.custom_emit(&self.cm
, Suggestion(sp
, suggestion
), msg
, Help
);
168 pub fn fileline_note(&self, sp
: Span
, msg
: &str) {
169 self.handler
.custom_emit(&self.cm
, FileLine(sp
), msg
, Note
);
171 pub fn fileline_help(&self, sp
: Span
, msg
: &str) {
172 self.handler
.custom_emit(&self.cm
, FileLine(sp
), msg
, Help
);
174 pub fn span_bug(&self, sp
: Span
, msg
: &str) -> ! {
175 self.handler
.emit(Some((&self.cm
, sp
)), msg
, Bug
);
178 pub fn span_unimpl(&self, sp
: Span
, msg
: &str) -> ! {
179 self.span_bug(sp
, &format
!("unimplemented {}", msg
));
181 pub fn handler
<'a
>(&'a
self) -> &'a Handler
{
186 /// A handler deals with errors; certain errors
187 /// (fatal, bug, unimpl) may cause immediate exit,
188 /// others log errors for later reporting.
190 err_count
: Cell
<usize>,
191 emit
: RefCell
<Box
<Emitter
+ Send
>>,
192 pub can_emit_warnings
: bool
196 pub fn new(color_config
: ColorConfig
,
197 registry
: Option
<diagnostics
::registry
::Registry
>,
198 can_emit_warnings
: bool
) -> Handler
{
199 let emitter
= Box
::new(EmitterWriter
::stderr(color_config
, registry
));
200 Handler
::with_emitter(can_emit_warnings
, emitter
)
202 pub fn with_emitter(can_emit_warnings
: bool
, e
: Box
<Emitter
+ Send
>) -> Handler
{
204 err_count
: Cell
::new(0),
205 emit
: RefCell
::new(e
),
206 can_emit_warnings
: can_emit_warnings
209 pub fn fatal(&self, msg
: &str) -> ! {
210 self.emit
.borrow_mut().emit(None
, msg
, None
, Fatal
);
213 pub fn err(&self, msg
: &str) {
214 self.emit
.borrow_mut().emit(None
, msg
, None
, Error
);
215 self.bump_err_count();
217 pub fn bump_err_count(&self) {
218 self.err_count
.set(self.err_count
.get() + 1);
220 pub fn err_count(&self) -> usize {
223 pub fn has_errors(&self) -> bool
{
224 self.err_count
.get() > 0
226 pub fn abort_if_errors(&self) {
228 match self.err_count
.get() {
230 1 => s
= "aborting due to previous error".to_string(),
232 s
= format
!("aborting due to {} previous errors",
233 self.err_count
.get());
238 pub fn warn(&self, msg
: &str) {
239 self.emit
.borrow_mut().emit(None
, msg
, None
, Warning
);
241 pub fn note(&self, msg
: &str) {
242 self.emit
.borrow_mut().emit(None
, msg
, None
, Note
);
244 pub fn help(&self, msg
: &str) {
245 self.emit
.borrow_mut().emit(None
, msg
, None
, Help
);
247 pub fn bug(&self, msg
: &str) -> ! {
248 self.emit
.borrow_mut().emit(None
, msg
, None
, Bug
);
251 pub fn unimpl(&self, msg
: &str) -> ! {
252 self.bug(&format
!("unimplemented {}", msg
));
255 cmsp
: Option
<(&codemap
::CodeMap
, Span
)>,
258 if lvl
== Warning
&& !self.can_emit_warnings { return }
259 self.emit
.borrow_mut().emit(cmsp
, msg
, None
, lvl
);
261 pub fn emit_with_code(&self,
262 cmsp
: Option
<(&codemap
::CodeMap
, Span
)>,
266 if lvl
== Warning
&& !self.can_emit_warnings { return }
267 self.emit
.borrow_mut().emit(cmsp
, msg
, Some(code
), lvl
);
269 pub fn custom_emit(&self, cm
: &codemap
::CodeMap
,
270 sp
: RenderSpan
, msg
: &str, lvl
: Level
) {
271 if lvl
== Warning
&& !self.can_emit_warnings { return }
272 self.emit
.borrow_mut().custom_emit(cm
, sp
, msg
, lvl
);
276 #[derive(Copy, PartialEq, Clone, Debug)]
286 impl fmt
::Display
for Level
{
287 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
288 use std
::fmt
::Display
;
291 Bug
=> "error: internal compiler error".fmt(f
),
292 Fatal
| Error
=> "error".fmt(f
),
293 Warning
=> "warning".fmt(f
),
294 Note
=> "note".fmt(f
),
295 Help
=> "help".fmt(f
),
301 fn color(self) -> term
::color
::Color
{
303 Bug
| Fatal
| Error
=> term
::color
::BRIGHT_RED
,
304 Warning
=> term
::color
::BRIGHT_YELLOW
,
305 Note
=> term
::color
::BRIGHT_GREEN
,
306 Help
=> term
::color
::BRIGHT_CYAN
,
311 fn print_maybe_styled(w
: &mut EmitterWriter
,
313 color
: term
::attr
::Attr
) -> io
::Result
<()> {
315 Terminal(ref mut t
) => {
317 // If `msg` ends in a newline, we need to reset the color before
318 // the newline. We're making the assumption that we end up writing
319 // to a `LineBufferedWriter`, which means that emitting the reset
320 // after the newline ends up buffering the reset until we print
321 // another line or exit. Buffering the reset is a problem if we're
322 // sharing the terminal with any other programs (e.g. other rustc
323 // instances via `make -jN`).
325 // Note that if `msg` contains any internal newlines, this will
326 // result in the `LineBufferedWriter` flushing twice instead of
327 // once, which still leaves the opportunity for interleaved output
328 // to be miscolored. We assume this is rare enough that we don't
329 // have to worry about it.
330 if msg
.ends_with("\n") {
331 try
!(t
.write_all(msg
[..msg
.len()-1].as_bytes()));
333 try
!(t
.write_all(b
"\n"));
335 try
!(t
.write_all(msg
.as_bytes()));
340 Raw(ref mut w
) => w
.write_all(msg
.as_bytes()),
344 fn print_diagnostic(dst
: &mut EmitterWriter
, topic
: &str, lvl
: Level
,
345 msg
: &str, code
: Option
<&str>) -> io
::Result
<()> {
346 if !topic
.is_empty() {
347 try
!(write
!(&mut dst
.dst
, "{} ", topic
));
350 try
!(print_maybe_styled(dst
,
351 &format
!("{}: ", lvl
.to_string()),
352 term
::attr
::ForegroundColor(lvl
.color())));
353 try
!(print_maybe_styled(dst
,
359 let style
= term
::attr
::ForegroundColor(term
::color
::BRIGHT_MAGENTA
);
360 try
!(print_maybe_styled(dst
, &format
!(" [{}]", code
.clone()), style
));
364 try
!(write
!(&mut dst
.dst
, "\n"));
368 pub struct EmitterWriter
{
370 registry
: Option
<diagnostics
::registry
::Registry
>
374 Terminal(Box
<term
::Terminal
<WriterWrapper
> + Send
>),
375 Raw(Box
<Write
+ Send
>),
379 pub fn stderr(color_config
: ColorConfig
,
380 registry
: Option
<diagnostics
::registry
::Registry
>) -> EmitterWriter
{
381 let stderr
= io
::stderr();
383 let use_color
= match color_config
{
386 Auto
=> stderr_isatty(),
390 let dst
= match term
::stderr() {
391 Some(t
) => Terminal(t
),
392 None
=> Raw(Box
::new(stderr
)),
394 EmitterWriter { dst: dst, registry: registry }
396 EmitterWriter { dst: Raw(Box::new(stderr)), registry: registry }
400 pub fn new(dst
: Box
<Write
+ Send
>,
401 registry
: Option
<diagnostics
::registry
::Registry
>) -> EmitterWriter
{
402 EmitterWriter { dst: Raw(dst), registry: registry }
407 fn stderr_isatty() -> bool
{
408 unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
411 fn stderr_isatty() -> bool
{
412 const STD_ERROR_HANDLE
: libc
::DWORD
= -12i32 as libc
::DWORD
;
414 fn GetStdHandle(which
: libc
::DWORD
) -> libc
::HANDLE
;
415 fn GetConsoleMode(hConsoleHandle
: libc
::HANDLE
,
416 lpMode
: libc
::LPDWORD
) -> libc
::BOOL
;
419 let handle
= GetStdHandle(STD_ERROR_HANDLE
);
421 GetConsoleMode(handle
, &mut out
) != 0
425 impl Write
for Destination
{
426 fn write(&mut self, bytes
: &[u8]) -> io
::Result
<usize> {
428 Terminal(ref mut t
) => t
.write(bytes
),
429 Raw(ref mut w
) => w
.write(bytes
),
432 fn flush(&mut self) -> io
::Result
<()> {
434 Terminal(ref mut t
) => t
.flush(),
435 Raw(ref mut w
) => w
.flush(),
440 impl Emitter
for EmitterWriter
{
442 cmsp
: Option
<(&codemap
::CodeMap
, Span
)>,
443 msg
: &str, code
: Option
<&str>, lvl
: Level
) {
444 let error
= match cmsp
{
445 Some((cm
, COMMAND_LINE_SP
)) => emit(self, cm
,
446 FileLine(COMMAND_LINE_SP
),
448 Some((cm
, sp
)) => emit(self, cm
, FullSpan(sp
), msg
, code
, lvl
),
449 None
=> print_diagnostic(self, "", lvl
, msg
, code
),
454 Err(e
) => panic
!("failed to print diagnostics: {:?}", e
),
458 fn custom_emit(&mut self, cm
: &codemap
::CodeMap
,
459 sp
: RenderSpan
, msg
: &str, lvl
: Level
) {
460 match emit(self, cm
, sp
, msg
, None
, lvl
) {
462 Err(e
) => panic
!("failed to print diagnostics: {:?}", e
),
467 fn emit(dst
: &mut EmitterWriter
, cm
: &codemap
::CodeMap
, rsp
: RenderSpan
,
468 msg
: &str, code
: Option
<&str>, lvl
: Level
) -> io
::Result
<()> {
471 // We cannot check equality directly with COMMAND_LINE_SP
472 // since PartialEq is manually implemented to ignore the ExpnId
473 let ss
= if sp
.expn_id
== COMMAND_LINE_EXPN
{
474 "<command line option>".to_string()
475 } else if let EndSpan(_
) = rsp
{
476 let span_end
= Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id}
;
477 cm
.span_to_string(span_end
)
479 cm
.span_to_string(sp
)
482 try
!(print_diagnostic(dst
, &ss
[..], lvl
, msg
, code
));
486 try
!(highlight_lines(dst
, cm
, sp
, lvl
, cm
.span_to_lines(sp
)));
487 try
!(print_macro_backtrace(dst
, cm
, sp
));
490 try
!(end_highlight_lines(dst
, cm
, sp
, lvl
, cm
.span_to_lines(sp
)));
491 try
!(print_macro_backtrace(dst
, cm
, sp
));
493 Suggestion(_
, ref suggestion
) => {
494 try
!(highlight_suggestion(dst
, cm
, sp
, suggestion
));
495 try
!(print_macro_backtrace(dst
, cm
, sp
));
498 // no source text in this case!
504 match dst
.registry
.as_ref().and_then(|registry
| registry
.find_description(code
)) {
506 try
!(print_diagnostic(dst
, &ss
[..], Help
,
507 &format
!("run `rustc --explain {}` to see a detailed \
508 explanation", code
), None
));
517 fn highlight_suggestion(err
: &mut EmitterWriter
,
518 cm
: &codemap
::CodeMap
,
523 let lines
= cm
.span_to_lines(sp
).unwrap();
524 assert
!(!lines
.lines
.is_empty());
526 // To build up the result, we want to take the snippet from the first
527 // line that precedes the span, prepend that with the suggestion, and
528 // then append the snippet from the last line that trails the span.
529 let fm
= &lines
.file
;
531 let first_line
= &lines
.lines
[0];
532 let prefix
= fm
.get_line(first_line
.line_index
)
533 .map(|l
| &l
[..first_line
.start_col
.0])
536 let last_line
= lines
.lines
.last().unwrap();
537 let suffix
= fm
.get_line(last_line
.line_index
)
538 .map(|l
| &l
[last_line
.end_col
.0..])
541 let complete
= format
!("{}{}{}", prefix
, suggestion
, suffix
);
543 // print the suggestion without any line numbers, but leave
544 // space for them. This helps with lining up with previous
545 // snippets from the actual error being reported.
546 let fm
= &*lines
.file
;
547 let mut lines
= complete
.lines();
548 for (line
, line_index
) in lines
.by_ref().take(MAX_LINES
).zip(first_line
.line_index
..) {
549 let elided_line_num
= format
!("{}", line_index
+1);
550 try
!(write
!(&mut err
.dst
, "{0}:{1:2$} {3}\n",
551 fm
.name
, "", elided_line_num
.len(), line
));
554 // if we elided some lines, add an ellipsis
555 if lines
.next().is_some() {
556 let elided_line_num
= format
!("{}", first_line
.line_index
+ MAX_LINES
+ 1);
557 try
!(write
!(&mut err
.dst
, "{0:1$} {0:2$} ...\n",
558 "", fm
.name
.len(), elided_line_num
.len()));
564 fn highlight_lines(err
: &mut EmitterWriter
,
565 cm
: &codemap
::CodeMap
,
568 lines
: codemap
::FileLinesResult
)
571 let lines
= match lines
{
574 try
!(write
!(&mut err
.dst
, "(internal compiler error: unprintable span)\n"));
579 let fm
= &*lines
.file
;
581 let line_strings
: Option
<Vec
<&str>> =
583 .map(|info
| fm
.get_line(info
.line_index
))
586 let line_strings
= match line_strings
{
587 None
=> { return Ok(()); }
588 Some(line_strings
) => line_strings
591 // Display only the first MAX_LINES lines.
592 let all_lines
= lines
.lines
.len();
593 let display_lines
= cmp
::min(all_lines
, MAX_LINES
);
594 let display_line_infos
= &lines
.lines
[..display_lines
];
595 let display_line_strings
= &line_strings
[..display_lines
];
597 // Print the offending lines
598 for (line_info
, line
) in display_line_infos
.iter().zip(display_line_strings
) {
599 try
!(write
!(&mut err
.dst
, "{}:{} {}\n",
601 line_info
.line_index
+ 1,
605 // If we elided something, put an ellipsis.
606 if display_lines
< all_lines
{
607 let last_line_index
= display_line_infos
.last().unwrap().line_index
;
608 let s
= format
!("{}:{} ", fm
.name
, last_line_index
+ 1);
609 try
!(write
!(&mut err
.dst
, "{0:1$}...\n", "", s
.len()));
613 // If there's one line at fault we can easily point to the problem
614 if lines
.lines
.len() == 1 {
615 let lo
= cm
.lookup_char_pos(sp
.lo
);
617 let mut num
= (lines
.lines
[0].line_index
+ 1) / 10;
619 // how many digits must be indent past?
620 while num
> 0 { num /= 10; digits += 1; }
622 let mut s
= String
::new();
623 // Skip is the number of characters we need to skip because they are
624 // part of the 'filename:line ' part of the previous line.
625 let skip
= fm
.name
.chars().count() + digits
+ 3;
629 if let Some(orig
) = fm
.get_line(lines
.lines
[0].line_index
) {
632 let mut iter
= orig
.chars().enumerate();
633 for (pos
, ch
) in iter
.by_ref() {
635 if pos
>= lo
.col
.to_usize() { break; }
636 // Whenever a tab occurs on the previous line, we insert one on
637 // the error-point-squiggly-line as well (instead of a space).
638 // That way the squiggly line will usually appear in the correct
652 try
!(write
!(&mut err
.dst
, "{}", s
));
653 let mut s
= String
::from("^");
654 let count
= match lastc
{
655 // Most terminals have a tab stop every eight columns by default
660 s
.extend(::std
::iter
::repeat('
~'
).take(count
));
662 let hi
= cm
.lookup_char_pos(sp
.hi
);
663 if hi
.col
!= lo
.col
{
664 for (pos
, ch
) in iter
{
665 if pos
>= hi
.col
.to_usize() { break; }
666 let count
= match ch
{
671 s
.extend(::std
::iter
::repeat('
~'
).take(count
));
676 // One extra squiggly is replaced by a "^"
680 try
!(print_maybe_styled(err
,
682 term
::attr
::ForegroundColor(lvl
.color())));
688 /// Here are the differences between this and the normal `highlight_lines`:
689 /// `end_highlight_lines` will always put arrow on the last byte of the
690 /// span (instead of the first byte). Also, when the span is too long (more
691 /// than 6 lines), `end_highlight_lines` will print the first line, then
692 /// dot dot dot, then last line, whereas `highlight_lines` prints the first
695 fn end_highlight_lines(w
: &mut EmitterWriter
,
696 cm
: &codemap
::CodeMap
,
699 lines
: codemap
::FileLinesResult
)
701 let lines
= match lines
{
704 try
!(write
!(&mut w
.dst
, "(internal compiler error: unprintable span)\n"));
709 let fm
= &*lines
.file
;
711 let lines
= &lines
.lines
[..];
712 if lines
.len() > MAX_LINES
{
713 if let Some(line
) = fm
.get_line(lines
[0].line_index
) {
714 try
!(write
!(&mut w
.dst
, "{}:{} {}\n", fm
.name
,
715 lines
[0].line_index
+ 1, line
));
717 try
!(write
!(&mut w
.dst
, "...\n"));
718 let last_line_index
= lines
[lines
.len() - 1].line_index
;
719 if let Some(last_line
) = fm
.get_line(last_line_index
) {
720 try
!(write
!(&mut w
.dst
, "{}:{} {}\n", fm
.name
,
721 last_line_index
+ 1, last_line
));
724 for line_info
in lines
{
725 if let Some(line
) = fm
.get_line(line_info
.line_index
) {
726 try
!(write
!(&mut w
.dst
, "{}:{} {}\n", fm
.name
,
727 line_info
.line_index
+ 1, line
));
731 let last_line_start
= format
!("{}:{} ", fm
.name
, lines
[lines
.len()-1].line_index
+ 1);
732 let hi
= cm
.lookup_char_pos(sp
.hi
);
733 let skip
= last_line_start
.chars().count();
734 let mut s
= String
::new();
738 if let Some(orig
) = fm
.get_line(lines
[0].line_index
) {
739 let iter
= orig
.chars().enumerate();
740 for (pos
, ch
) in iter
{
741 // Span seems to use half-opened interval, so subtract 1
742 if pos
>= hi
.col
.to_usize() - 1 { break; }
743 // Whenever a tab occurs on the previous line, we insert one on
744 // the error-point-squiggly-line as well (instead of a space).
745 // That way the squiggly line will usually appear in the correct
748 '
\t'
=> s
.push('
\t'
),
755 print_maybe_styled(w
,
757 term
::attr
::ForegroundColor(lvl
.color()))
760 fn print_macro_backtrace(w
: &mut EmitterWriter
,
761 cm
: &codemap
::CodeMap
,
764 let cs
= try
!(cm
.with_expn_info(sp
.expn_id
, |expn_info
| -> io
::Result
<_
> {
767 let ss
= ei
.callee
.span
.map_or(String
::new(),
768 |span
| cm
.span_to_string(span
));
769 let (pre
, post
) = match ei
.callee
.format
{
770 codemap
::MacroAttribute
=> ("#[", "]"),
771 codemap
::MacroBang
=> ("", "!"),
772 codemap
::CompilerExpansion
=> ("", ""),
774 try
!(print_diagnostic(w
, &ss
, Note
,
775 &format
!("in expansion of {}{}{}",
780 let ss
= cm
.span_to_string(ei
.call_site
);
781 try
!(print_diagnostic(w
, &ss
, Note
, "expansion site", None
));
782 Ok(Some(ei
.call_site
))
787 cs
.map_or(Ok(()), |call_site
| print_macro_backtrace(w
, cm
, call_site
))
790 pub fn expect
<T
, M
>(diag
: &SpanHandler
, opt
: Option
<T
>, msg
: M
) -> T
where
791 M
: FnOnce() -> String
,
795 None
=> diag
.handler().bug(&msg()),