diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 5c5e6303b8243..9a5c726901fe8 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -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. diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index d04b9ac083ce5..bb4ef2d7bd426 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -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(&self, f: F) -> Result where F: FnOnce() -> T, @@ -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) - } -} diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 05cee6dff2309..70bd25a9d5772 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -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>, continue_after_error: AtomicBool, delayed_span_bugs: Lock>, @@ -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(..) { @@ -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()), @@ -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); } @@ -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; @@ -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 { @@ -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) { diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 69cb696f4c580..c1b6e3409c915 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -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); } diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 67bcd4943e79a..887ef4b520ea3 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -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}; @@ -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) { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 5623016c2e5e7..392a46a262f50 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -1022,6 +1022,12 @@ impl<'a> Resolver<'a> { fn suggest_macro_name(&mut self, name: Symbol, kind: MacroKind, err: &mut DiagnosticBuilder<'a>, span: Span) { + if kind == MacroKind::Derive && (name.as_str() == "Send" || name.as_str() == "Sync") { + let msg = format!("unsafe traits like `{}` should be implemented explicitly", name); + err.span_note(span, &msg); + return; + } + // First check if this is a locally-defined bang macro. let suggestion = if let MacroKind::Bang = kind { find_best_match_for_name( diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 5831b0bcd8fa3..8905f475647ba 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -2,8 +2,6 @@ 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::*; @@ -11,16 +9,12 @@ 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, } impl<'a> SpanUtils<'a> { pub fn new(sess: &'a Session) -> SpanUtils<'a> { SpanUtils { sess, - err_count: Cell::new(0), } } diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 8ca1b85ad9aee..85da325197143 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -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; @@ -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. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0ec5c9763a0fb..b53159fc6e1ef 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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>>, @@ -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) { @@ -2128,8 +2128,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 @@ -4375,7 +4375,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()); return; } } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 5c710399446ef..5313e1d0f73a3 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -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); @@ -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)); } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index ec0f431d9b25e..b505679cad037 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -320,6 +320,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() { @@ -352,7 +353,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() { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 7da501ef6cb74..29ee59d124274 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -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"); } diff --git a/src/libsyntax_ext/deriving/bounds.rs b/src/libsyntax_ext/deriving/bounds.rs index c7b805e0bdca6..d5b8a00c75b83 100644 --- a/src/libsyntax_ext/deriving/bounds.rs +++ b/src/libsyntax_ext/deriving/bounds.rs @@ -6,14 +6,6 @@ use syntax::ast::MetaItem; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax_pos::Span; -pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt<'_>, - span: Span, - _: &MetaItem, - _: &Annotatable, - _: &mut dyn FnMut(Annotatable)) { - cx.span_err(span, "this unsafe trait should be implemented explicitly"); -} - pub fn expand_deriving_copy(cx: &mut ExtCtxt<'_>, span: Span, mitem: &MetaItem, diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index e75eff2e85714..aa9913d436cfa 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -111,8 +111,6 @@ derive_traits! { "Default" => default::expand_deriving_default, - "Send" => bounds::expand_deriving_unsafe_bound, - "Sync" => bounds::expand_deriving_unsafe_bound, "Copy" => bounds::expand_deriving_copy, // deprecated diff --git a/src/test/ui/consts/enum-discr-type-err.rs b/src/test/ui/consts/enum-discr-type-err.rs new file mode 100644 index 0000000000000..d66c4f47d03ee --- /dev/null +++ b/src/test/ui/consts/enum-discr-type-err.rs @@ -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() {} diff --git a/src/test/ui/consts/enum-discr-type-err.stderr b/src/test/ui/consts/enum-discr-type-err.stderr new file mode 100644 index 0000000000000..3c4fac7327d40 --- /dev/null +++ b/src/test/ui/consts/enum-discr-type-err.stderr @@ -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`. diff --git a/src/test/ui/derives/deriving-bounds.rs b/src/test/ui/derives/deriving-bounds.rs index 607cfa1bb2cd7..52659bd11e080 100644 --- a/src/test/ui/derives/deriving-bounds.rs +++ b/src/test/ui/derives/deriving-bounds.rs @@ -1,9 +1,9 @@ #[derive(Send)] -//~^ ERROR this unsafe trait should be implemented explicitly +//~^ ERROR cannot find derive macro `Send` in this scope struct Test; #[derive(Sync)] -//~^ ERROR this unsafe trait should be implemented explicitly +//~^ ERROR cannot find derive macro `Sync` in this scope struct Test1; pub fn main() {} diff --git a/src/test/ui/derives/deriving-bounds.stderr b/src/test/ui/derives/deriving-bounds.stderr index deb84fd99bd2a..99976da72da1d 100644 --- a/src/test/ui/derives/deriving-bounds.stderr +++ b/src/test/ui/derives/deriving-bounds.stderr @@ -1,10 +1,22 @@ -error: this unsafe trait should be implemented explicitly +error: cannot find derive macro `Send` in this scope + --> $DIR/deriving-bounds.rs:1:10 + | +LL | #[derive(Send)] + | ^^^^ + | +note: unsafe traits like `Send` should be implemented explicitly --> $DIR/deriving-bounds.rs:1:10 | LL | #[derive(Send)] | ^^^^ -error: this unsafe trait should be implemented explicitly +error: cannot find derive macro `Sync` in this scope + --> $DIR/deriving-bounds.rs:5:10 + | +LL | #[derive(Sync)] + | ^^^^ + | +note: unsafe traits like `Sync` should be implemented explicitly --> $DIR/deriving-bounds.rs:5:10 | LL | #[derive(Sync)] diff --git a/src/test/ui/issues/issue-33571.rs b/src/test/ui/issues/issue-33571.rs index 223bbc3ff5e21..147fb3fa8cf33 100644 --- a/src/test/ui/issues/issue-33571.rs +++ b/src/test/ui/issues/issue-33571.rs @@ -1,5 +1,5 @@ #[derive(Clone, - Sync, //~ ERROR this unsafe trait should be implemented explicitly + Sync, //~ ERROR cannot find derive macro `Sync` in this scope Copy)] enum Foo {} diff --git a/src/test/ui/issues/issue-33571.stderr b/src/test/ui/issues/issue-33571.stderr index 5d83a08e90757..78e7202077498 100644 --- a/src/test/ui/issues/issue-33571.stderr +++ b/src/test/ui/issues/issue-33571.stderr @@ -1,4 +1,10 @@ -error: this unsafe trait should be implemented explicitly +error: cannot find derive macro `Sync` in this scope + --> $DIR/issue-33571.rs:2:10 + | +LL | Sync, + | ^^^^ + | +note: unsafe traits like `Sync` should be implemented explicitly --> $DIR/issue-33571.rs:2:10 | LL | Sync, diff --git a/src/test/ui/issues/issue-38591.rs b/src/test/ui/issues/issue-38591.rs new file mode 100644 index 0000000000000..7aa71f8b9eb9b --- /dev/null +++ b/src/test/ui/issues/issue-38591.rs @@ -0,0 +1,10 @@ +// run-pass + +struct S { + t : T, + s : Box> +} + +fn f(x : S) {} + +fn main () {}