Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix error counting #62055

Merged
merged 2 commits into from
Jun 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ pub struct InferCtxt<'a, 'tcx> {
/// Track how many errors were reported when this infcx is created.
/// If the number of errors increases, that's also a sign (line
/// `tained_by_errors`) to avoid reporting certain kinds of errors.
// FIXME(matthewjasper) Merge into `tainted_by_errors_flag`
err_count_on_creation: usize,

/// This flag is true while there is an active snapshot.
Expand Down
15 changes: 6 additions & 9 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,13 @@ impl Session {
self.diagnostic().abort_if_errors();
}
pub fn compile_status(&self) -> Result<(), ErrorReported> {
compile_result_from_err_count(self.err_count())
if self.has_errors() {
Err(ErrorReported)
} else {
Ok(())
}
}
// FIXME(matthewjasper) Remove this method, it should never be needed.
pub fn track_errors<F, T>(&self, f: F) -> Result<T, ErrorReported>
where
F: FnOnce() -> T,
Expand Down Expand Up @@ -1388,11 +1393,3 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
}

pub type CompileResult = Result<(), ErrorReported>;

pub fn compile_result_from_err_count(err_count: usize) -> CompileResult {
if err_count == 0 {
Ok(())
} else {
Err(ErrorReported)
}
}
23 changes: 16 additions & 7 deletions src/librustc_errors/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,12 @@ pub use diagnostic_builder::DiagnosticBuilder;
pub struct Handler {
pub flags: HandlerFlags,

/// The number of errors that have been emitted, including duplicates.
///
/// This is not necessarily the count that's reported to the user once
/// compilation ends.
err_count: AtomicUsize,
deduplicated_err_count: AtomicUsize,
emitter: Lock<Box<dyn Emitter + sync::Send>>,
continue_after_error: AtomicBool,
delayed_span_bugs: Lock<Vec<Diagnostic>>,
Expand Down Expand Up @@ -352,7 +357,7 @@ pub struct HandlerFlags {

impl Drop for Handler {
fn drop(&mut self) {
if self.err_count() == 0 {
if !self.has_errors() {
let mut bugs = self.delayed_span_bugs.borrow_mut();
let has_bugs = !bugs.is_empty();
for bug in bugs.drain(..) {
Expand Down Expand Up @@ -407,6 +412,7 @@ impl Handler {
Handler {
flags,
err_count: AtomicUsize::new(0),
deduplicated_err_count: AtomicUsize::new(0),
emitter: Lock::new(e),
continue_after_error: AtomicBool::new(true),
delayed_span_bugs: Lock::new(Vec::new()),
Expand All @@ -428,6 +434,7 @@ impl Handler {
pub fn reset_err_count(&self) {
// actually frees the underlying memory (which `clear` would not do)
*self.emitted_diagnostics.borrow_mut() = Default::default();
self.deduplicated_err_count.store(0, SeqCst);
self.err_count.store(0, SeqCst);
}

Expand Down Expand Up @@ -660,10 +667,10 @@ impl Handler {
}

pub fn print_error_count(&self, registry: &Registry) {
let s = match self.err_count() {
let s = match self.deduplicated_err_count.load(SeqCst) {
0 => return,
1 => "aborting due to previous error".to_string(),
_ => format!("aborting due to {} previous errors", self.err_count())
count => format!("aborting due to {} previous errors", count)
};
if self.treat_err_as_bug() {
return;
Expand Down Expand Up @@ -705,10 +712,9 @@ impl Handler {
}

pub fn abort_if_errors(&self) {
if self.err_count() == 0 {
return;
if self.has_errors() {
FatalError.raise();
}
FatalError.raise();
}
pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
if lvl == Warning && !self.flags.can_emit_warnings {
Expand Down Expand Up @@ -770,9 +776,12 @@ impl Handler {
if self.emitted_diagnostics.borrow_mut().insert(diagnostic_hash) {
self.emitter.borrow_mut().emit_diagnostic(db);
if db.is_error() {
self.bump_err_count();
self.deduplicated_err_count.fetch_add(1, SeqCst);
}
}
if db.is_error() {
self.bump_err_count();
}
}

pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_interface/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,7 @@ fn analysis<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> Result<()> {
// lot of annoying errors in the compile-fail tests (basically,
// lint warnings and so on -- kindck used to do this abort, but
// kindck is gone now). -nmatsakis
if sess.err_count() > 0 {
if sess.has_errors() {
return Err(ErrorReported);
}

Expand Down
20 changes: 6 additions & 14 deletions src/librustc_mir/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
use rustc::ty::layout::{self, LayoutOf, VariantIdx};
use rustc::ty::subst::Subst;
use rustc::traits::Reveal;
use rustc::util::common::ErrorReported;
use rustc_data_structures::fx::FxHashMap;

use syntax::source_map::{Span, DUMMY_SP};
Expand Down Expand Up @@ -655,19 +654,12 @@ pub fn const_eval_raw_provider<'tcx>(
if tcx.is_static(def_id) {
// Ensure that if the above error was either `TooGeneric` or `Reported`
// an error must be reported.
let reported_err = tcx.sess.track_errors(|| {
err.report_as_error(ecx.tcx,
"could not evaluate static initializer")
});
match reported_err {
Ok(v) => {
tcx.sess.delay_span_bug(err.span,
&format!("static eval failure did not emit an error: {:#?}",
v));
v
},
Err(ErrorReported) => ErrorHandled::Reported,
}
let v = err.report_as_error(ecx.tcx, "could not evaluate static initializer");
tcx.sess.delay_span_bug(
err.span,
&format!("static eval failure did not emit an error: {:#?}", v)
);
v
} else if def_id.is_local() {
// constant defined in this crate, we can figure out a lint level!
match tcx.def_kind(def_id) {
Expand Down
6 changes: 0 additions & 6 deletions src/librustc_save_analysis/span_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,19 @@ use rustc::session::Session;

use crate::generated_code;

use std::cell::Cell;

use syntax::parse::lexer::{self, StringReader};
use syntax::parse::token::{self, TokenKind};
use syntax_pos::*;

#[derive(Clone)]
pub struct SpanUtils<'a> {
pub sess: &'a Session,
// FIXME given that we clone SpanUtils all over the place, this err_count is
// probably useless and any logic relying on it is bogus.
pub err_count: Cell<isize>,
}

impl<'a> SpanUtils<'a> {
pub fn new(sess: &'a Session) -> SpanUtils<'a> {
SpanUtils {
sess,
err_count: Cell::new(0),
}
}

Expand Down
8 changes: 3 additions & 5 deletions src/librustc_typeck/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// else an error would have been flagged by the
// `loops` pass for using break with an expression
// where you are not supposed to.
assert!(expr_opt.is_none() || self.tcx.sess.err_count() > 0);
assert!(expr_opt.is_none() || self.tcx.sess.has_errors());
}

ctxt.may_break = true;
Expand All @@ -577,10 +577,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// this can only happen if the `break` was not
// inside a loop at all, which is caught by the
// loop-checking pass.
if self.tcx.sess.err_count() == 0 {
self.tcx.sess.delay_span_bug(expr.span,
"break was outside loop, but no error was emitted");
}
self.tcx.sess.delay_span_bug(expr.span,
"break was outside loop, but no error was emitted");

// We still need to assign a type to the inner expression to
// prevent the ICE in #43162.
Expand Down
16 changes: 8 additions & 8 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,8 @@ pub struct FnCtxt<'a, 'tcx> {
/// checking this function. On exit, if we find that *more* errors
/// have been reported, we will skip regionck and other work that
/// expects the types within the function to be consistent.
// FIXME(matthewjasper) This should not exist, and it's not correct
// if type checking is run in parallel.
err_count_on_creation: usize,

ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
Expand Down Expand Up @@ -696,11 +698,9 @@ impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> {
fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) { }
}

pub fn check_wf_new<'tcx>(tcx: TyCtxt<'tcx>) -> Result<(), ErrorReported> {
tcx.sess.track_errors(|| {
let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
tcx.hir().krate().par_visit_all_item_likes(&mut visit);
})
pub fn check_wf_new<'tcx>(tcx: TyCtxt<'tcx>) {
let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
tcx.hir().krate().par_visit_all_item_likes(&mut visit);
}

fn check_mod_item_types<'tcx>(tcx: TyCtxt<'tcx>, module_def_id: DefId) {
Expand Down Expand Up @@ -2129,8 +2129,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self.tcx.sess
}

pub fn err_count_since_creation(&self) -> usize {
self.tcx.sess.err_count() - self.err_count_on_creation
pub fn errors_reported_since_creation(&self) -> bool {
self.tcx.sess.err_count() > self.err_count_on_creation
}

/// Produces warning on the given node, if the current point in the
Expand Down Expand Up @@ -4376,7 +4376,7 @@ pub fn check_bounds_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, t
} else if let ty::Error = leaf_ty.sty {
// If there is already another error, do not emit
// an error for not using a type Parameter.
assert!(tcx.sess.err_count() > 0);
assert!(tcx.sess.has_errors());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code like this should probably be using delay_span_bug uniformly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer an EmittedError type only created by emitting errors and putting that in ty::Error instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's even nicer - we might want to use that in the AST and HIR as well.

But maybe it should be something less temporarily ordered, so if there is some place where ty::Error needs to be created but it's not the same place the errors is to be reported from, we can still create a proof that "some error has happened or will happen" with delay_span_bug.

return;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_typeck/check/regionck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// standalone expr (e.g., the `E` in a type like `[u32; E]`).
rcx.outlives_environment.save_implied_bounds(id);

if self.err_count_since_creation() == 0 {
if !self.errors_reported_since_creation() {
// regionck assumes typeck succeeded
rcx.visit_body(body);
rcx.visit_region_obligations(id);
Expand Down Expand Up @@ -173,7 +173,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.param_env,
);

if self.err_count_since_creation() == 0 {
if !self.errors_reported_since_creation() {
// regionck assumes typeck succeeded
rcx.visit_fn_body(fn_id, body, self.tcx.hir().span(fn_id));
}
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_typeck/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) -> Result<(), ErrorReported> {

// this ensures that later parts of type checking can assume that items
// have valid types and not error
// FIXME(matthewjasper) We shouldn't need to do this.
tcx.sess.track_errors(|| {
time(tcx.sess, "type collecting", || {
for &module in tcx.hir().krate().modules.keys() {
Expand Down Expand Up @@ -353,7 +354,9 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) -> Result<(), ErrorReported> {
})?;
}

time(tcx.sess, "wf checking", || check::check_wf_new(tcx))?;
tcx.sess.track_errors(|| {
time(tcx.sess, "wf checking", || check::check_wf_new(tcx));
})?;

time(tcx.sess, "item-types checking", || {
for &module in tcx.hir().krate().modules.keys() {
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
// current architecture.
let resolver = abort_on_err(compiler.expansion(), sess).peek().1.clone();

if sess.err_count() > 0 {
if sess.has_errors() {
sess.fatal("Compilation failed, aborting rustdoc");
}

Expand Down
29 changes: 29 additions & 0 deletions src/test/ui/consts/enum-discr-type-err.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Test that we mark enum discriminant values as having errors, even when the
// diagnostic is deduplicated.

struct F;
struct T;

impl F {
const V: i32 = 0;
}

impl T {
const V: i32 = 0;
}

macro_rules! mac {
($( $v: ident = $s: ident,)*) => {
enum E {
$( $v = $s::V, )*
//~^ ERROR mismatched types
}
}
}

mac! {
A = F,
B = T,
}

fn main() {}
19 changes: 19 additions & 0 deletions src/test/ui/consts/enum-discr-type-err.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0308]: mismatched types
--> $DIR/enum-discr-type-err.rs:18:21
|
LL | $( $v = $s::V, )*
| ^^^^^ expected isize, found i32
...
LL | / mac! {
LL | | A = F,
LL | | B = T,
LL | | }
| |_- in this macro invocation
help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit
|
LL | $( $v = $s::V.try_into().unwrap(), )*
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.