Skip to content

Commit 176ee34

Browse files
committed
Auto merge of #30542 - nrc:errs-base, r=nagisa
As discussed [here](https://internals.rust-lang.org/t/more-structured-errors/3005) r? @nikomatsakis or anyone else on the @rust-lang/compiler team
2 parents a06bb97 + 04d9729 commit 176ee34

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+2253
-1517
lines changed

src/librustc/lint/context.rs

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,14 @@ use std::mem;
4040
use syntax::ast_util::{self, IdVisitingOperation};
4141
use syntax::attr::{self, AttrMetaMethods};
4242
use syntax::codemap::Span;
43+
use syntax::errors::{self, DiagnosticBuilder};
4344
use syntax::parse::token::InternedString;
4445
use syntax::ast;
4546
use syntax::attr::ThinAttributesExt;
4647
use rustc_front::hir;
4748
use rustc_front::util;
4849
use rustc_front::intravisit as hir_visit;
4950
use syntax::visit as ast_visit;
50-
use syntax::errors;
5151

5252
/// Information about the registered lints.
5353
///
@@ -363,10 +363,24 @@ pub fn gather_attrs(attrs: &[ast::Attribute])
363363
/// in trans that run after the main lint pass is finished. Most
364364
/// lints elsewhere in the compiler should call
365365
/// `Session::add_lint()` instead.
366-
pub fn raw_emit_lint(sess: &Session, lint: &'static Lint,
367-
lvlsrc: LevelSource, span: Option<Span>, msg: &str) {
366+
pub fn raw_emit_lint(sess: &Session,
367+
lint: &'static Lint,
368+
lvlsrc: LevelSource,
369+
span: Option<Span>,
370+
msg: &str) {
371+
raw_struct_lint(sess, lint, lvlsrc, span, msg).emit();
372+
}
373+
374+
pub fn raw_struct_lint<'a>(sess: &'a Session,
375+
lint: &'static Lint,
376+
lvlsrc: LevelSource,
377+
span: Option<Span>,
378+
msg: &str)
379+
-> DiagnosticBuilder<'a> {
368380
let (mut level, source) = lvlsrc;
369-
if level == Allow { return }
381+
if level == Allow {
382+
return sess.diagnostic().struct_dummy();
383+
}
370384

371385
let name = lint.name_lower();
372386
let mut def = None;
@@ -391,17 +405,19 @@ pub fn raw_emit_lint(sess: &Session, lint: &'static Lint,
391405
// For purposes of printing, we can treat forbid as deny.
392406
if level == Forbid { level = Deny; }
393407

394-
match (level, span) {
395-
(Warn, Some(sp)) => sess.span_warn(sp, &msg[..]),
396-
(Warn, None) => sess.warn(&msg[..]),
397-
(Deny, Some(sp)) => sess.span_err(sp, &msg[..]),
398-
(Deny, None) => sess.err(&msg[..]),
408+
let mut err = match (level, span) {
409+
(Warn, Some(sp)) => sess.struct_span_warn(sp, &msg[..]),
410+
(Warn, None) => sess.struct_warn(&msg[..]),
411+
(Deny, Some(sp)) => sess.struct_span_err(sp, &msg[..]),
412+
(Deny, None) => sess.struct_err(&msg[..]),
399413
_ => sess.bug("impossible level in raw_emit_lint"),
400-
}
414+
};
401415

402416
if let Some(span) = def {
403-
sess.span_note(span, "lint level defined here");
417+
err.span_note(span, "lint level defined here");
404418
}
419+
420+
err
405421
}
406422

407423
pub trait LintContext: Sized {
@@ -418,44 +434,74 @@ pub trait LintContext: Sized {
418434
self.lints().levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl)
419435
}
420436

421-
fn lookup_and_emit(&self, lint: &'static Lint, span: Option<Span>, msg: &str) {
422-
let (level, src) = match self.lints().levels.get(&LintId::of(lint)) {
423-
None => return,
424-
Some(&(Warn, src)) => {
437+
fn level_src(&self, lint: &'static Lint) -> Option<LevelSource> {
438+
self.lints().levels.get(&LintId::of(lint)).map(|ls| match ls {
439+
&(Warn, src) => {
425440
let lint_id = LintId::of(builtin::WARNINGS);
426441
(self.lints().get_level_source(lint_id).0, src)
427442
}
428-
Some(&pair) => pair,
443+
_ => *ls
444+
})
445+
}
446+
447+
fn lookup_and_emit(&self, lint: &'static Lint, span: Option<Span>, msg: &str) {
448+
let (level, src) = match self.level_src(lint) {
449+
None => return,
450+
Some(pair) => pair,
429451
};
430452

431453
raw_emit_lint(&self.sess(), lint, (level, src), span, msg);
432454
}
433455

456+
fn lookup(&self,
457+
lint: &'static Lint,
458+
span: Option<Span>,
459+
msg: &str)
460+
-> DiagnosticBuilder {
461+
let (level, src) = match self.level_src(lint) {
462+
None => return self.sess().diagnostic().struct_dummy(),
463+
Some(pair) => pair,
464+
};
465+
466+
raw_struct_lint(&self.sess(), lint, (level, src), span, msg)
467+
}
468+
434469
/// Emit a lint at the appropriate level, for a particular span.
435470
fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) {
436471
self.lookup_and_emit(lint, Some(span), msg);
437472
}
438473

474+
fn struct_span_lint(&self,
475+
lint: &'static Lint,
476+
span: Span,
477+
msg: &str)
478+
-> DiagnosticBuilder {
479+
self.lookup(lint, Some(span), msg)
480+
}
481+
439482
/// Emit a lint and note at the appropriate level, for a particular span.
440483
fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str,
441484
note_span: Span, note: &str) {
442-
self.span_lint(lint, span, msg);
485+
let mut err = self.lookup(lint, Some(span), msg);
443486
if self.current_level(lint) != Level::Allow {
444487
if note_span == span {
445-
self.sess().fileline_note(note_span, note)
488+
err.fileline_note(note_span, note);
446489
} else {
447-
self.sess().span_note(note_span, note)
490+
err.span_note(note_span, note);
448491
}
449492
}
493+
err.emit();
450494
}
451495

452496
/// Emit a lint and help at the appropriate level, for a particular span.
453497
fn span_lint_help(&self, lint: &'static Lint, span: Span,
454498
msg: &str, help: &str) {
499+
let mut err = self.lookup(lint, Some(span), msg);
455500
self.span_lint(lint, span, msg);
456501
if self.current_level(lint) != Level::Allow {
457-
self.sess().span_help(span, help)
502+
err.span_help(span, help);
458503
}
504+
err.emit();
459505
}
460506

461507
/// Emit a lint at the appropriate level, with no associated span.

src/librustc/lint/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use rustc_front::hir;
4141

4242
pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
4343
raw_emit_lint, check_crate, check_ast_crate, gather_attrs,
44-
GatherNodeLevels};
44+
raw_struct_lint, GatherNodeLevels};
4545

4646
/// Specification of a single lint.
4747
#[derive(Copy, Clone, Debug)]

src/librustc/middle/check_const.rs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -224,14 +224,15 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
224224
// this doesn't come from a macro that has #[allow_internal_unstable]
225225
!self.tcx.sess.codemap().span_allows_unstable(expr.span)
226226
{
227-
self.tcx.sess.span_err(
227+
let mut err = self.tcx.sess.struct_span_err(
228228
expr.span,
229229
"const fns are an unstable feature");
230230
fileline_help!(
231-
self.tcx.sess,
231+
&mut err,
232232
expr.span,
233233
"in Nightly builds, add `#![feature(const_fn)]` to the crate \
234234
attributes to enable");
235+
err.emit();
235236
}
236237

237238
let qualif = self.fn_like(fn_like.kind(),
@@ -714,27 +715,27 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
714715
if !is_const {
715716
v.add_qualif(ConstQualif::NOT_CONST);
716717
if v.mode != Mode::Var {
717-
fn span_limited_call_error(tcx: &ty::ctxt, span: Span, s: &str) {
718-
span_err!(tcx.sess, span, E0015, "{}", s);
719-
}
720-
721718
// FIXME(#24111) Remove this check when const fn stabilizes
722-
if let UnstableFeatures::Disallow = v.tcx.sess.opts.unstable_features {
723-
span_limited_call_error(&v.tcx, e.span,
724-
&format!("function calls in {}s are limited to \
725-
struct and enum constructors",
726-
v.msg()));
727-
v.tcx.sess.span_note(e.span,
728-
"a limited form of compile-time function \
729-
evaluation is available on a nightly \
730-
compiler via `const fn`");
719+
let (msg, note) =
720+
if let UnstableFeatures::Disallow = v.tcx.sess.opts.unstable_features {
721+
(format!("function calls in {}s are limited to \
722+
struct and enum constructors",
723+
v.msg()),
724+
Some("a limited form of compile-time function \
725+
evaluation is available on a nightly \
726+
compiler via `const fn`"))
731727
} else {
732-
span_limited_call_error(&v.tcx, e.span,
733-
&format!("function calls in {}s are limited \
734-
to constant functions, \
735-
struct and enum constructors",
736-
v.msg()));
728+
(format!("function calls in {}s are limited \
729+
to constant functions, \
730+
struct and enum constructors",
731+
v.msg()),
732+
None)
733+
};
734+
let mut err = struct_span_err!(v.tcx.sess, e.span, E0015, "{}", msg);
735+
if let Some(note) = note {
736+
err.span_note(e.span, note);
737737
}
738+
err.emit();
738739
}
739740
}
740741
}

src/librustc/middle/check_match.rs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -215,12 +215,13 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
215215
if inlined_arms.is_empty() {
216216
if !pat_ty.is_empty(cx.tcx) {
217217
// We know the type is inhabited, so this must be wrong
218-
span_err!(cx.tcx.sess, ex.span, E0002,
219-
"non-exhaustive patterns: type {} is non-empty",
220-
pat_ty);
221-
span_help!(cx.tcx.sess, ex.span,
218+
let mut err = struct_span_err!(cx.tcx.sess, ex.span, E0002,
219+
"non-exhaustive patterns: type {} is non-empty",
220+
pat_ty);
221+
span_help!(&mut err, ex.span,
222222
"Please ensure that all possible cases are being handled; \
223223
possibly adding wildcards or more match arms.");
224+
err.emit();
224225
}
225226
// If the type *is* empty, it's vacuously exhaustive
226227
return;
@@ -251,14 +252,15 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat)
251252
&& variant.kind() == VariantKind::Unit
252253
) {
253254
let ty_path = cx.tcx.item_path_str(edef.did);
254-
span_warn!(cx.tcx.sess, p.span, E0170,
255+
let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
255256
"pattern binding `{}` is named the same as one \
256257
of the variants of the type `{}`",
257258
ident.node, ty_path);
258-
fileline_help!(cx.tcx.sess, p.span,
259+
fileline_help!(err, p.span,
259260
"if you meant to match on a variant, \
260261
consider making the path in the pattern qualified: `{}::{}`",
261262
ty_path, ident.node);
263+
err.emit();
262264
}
263265
}
264266
}
@@ -282,13 +284,13 @@ fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) {
282284
Ok(_) => {}
283285

284286
Err(err) => {
285-
span_err!(cx.tcx.sess, err.span, E0471,
286-
"constant evaluation error: {}",
287-
err.description());
287+
let mut diag = struct_span_err!(cx.tcx.sess, err.span, E0471,
288+
"constant evaluation error: {}",
289+
err.description());
288290
if !p.span.contains(err.span) {
289-
cx.tcx.sess.span_note(p.span,
290-
"in pattern here")
291+
diag.span_note(p.span, "in pattern here");
291292
}
293+
diag.emit();
292294
}
293295
}
294296
}
@@ -1076,9 +1078,10 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
10761078
} else if has_guard {
10771079
span_err!(cx.tcx.sess, p.span, E0008, "cannot bind by-move into a pattern guard");
10781080
} else if by_ref_span.is_some() {
1079-
span_err!(cx.tcx.sess, p.span, E0009,
1080-
"cannot bind by-move and by-ref in the same pattern");
1081-
span_note!(cx.tcx.sess, by_ref_span.unwrap(), "by-ref binding occurs here");
1081+
let mut err = struct_span_err!(cx.tcx.sess, p.span, E0009,
1082+
"cannot bind by-move and by-ref in the same pattern");
1083+
span_note!(&mut err, by_ref_span.unwrap(), "by-ref binding occurs here");
1084+
err.emit();
10821085
}
10831086
};
10841087

src/librustc/middle/dependency_format.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,11 @@ fn add_library(sess: &session::Session,
243243
// This error is probably a little obscure, but I imagine that it
244244
// can be refined over time.
245245
if link2 != link || link == RequireStatic {
246-
sess.err(&format!("cannot satisfy dependencies so `{}` only \
247-
shows up once", sess.cstore.crate_name(cnum)));
248-
sess.help("having upstream crates all available in one format \
249-
will likely make this go away");
246+
sess.struct_err(&format!("cannot satisfy dependencies so `{}` only \
247+
shows up once", sess.cstore.crate_name(cnum)))
248+
.help("having upstream crates all available in one format \
249+
will likely make this go away")
250+
.emit();
250251
}
251252
}
252253
None => { m.insert(cnum, link); }

src/librustc/middle/entry.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,17 +146,20 @@ fn configure_main(this: &mut EntryContext) {
146146
this.session.entry_type.set(Some(config::EntryMain));
147147
} else {
148148
// No main function
149-
this.session.err("main function not found");
149+
let mut err = this.session.struct_err("main function not found");
150150
if !this.non_main_fns.is_empty() {
151151
// There were some functions named 'main' though. Try to give the user a hint.
152-
this.session.note("the main function must be defined at the crate level \
153-
but you have one or more functions named 'main' that are not \
154-
defined at the crate level. Either move the definition or \
155-
attach the `#[main]` attribute to override this behavior.");
152+
err.note("the main function must be defined at the crate level \
153+
but you have one or more functions named 'main' that are not \
154+
defined at the crate level. Either move the definition or \
155+
attach the `#[main]` attribute to override this behavior.");
156156
for &(_, span) in &this.non_main_fns {
157-
this.session.span_note(span, "here is a function named 'main'");
157+
err.span_note(span, "here is a function named 'main'");
158158
}
159+
err.emit();
159160
this.session.abort_if_errors();
161+
} else {
162+
err.emit();
160163
}
161164
}
162165
}

0 commit comments

Comments
 (0)