diff options
189 files changed, 2575 insertions, 1411 deletions
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 84fe9ad2672..21183121e15 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -16,6 +16,7 @@ #![feature(min_specialization)] #![recursion_limit = "256"] #![feature(slice_internals)] +#![feature(stmt_expr_attributes)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 1cc5ddfd8ee..224afbd553f 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -56,25 +56,30 @@ impl LitKind { // new symbol because the string in the LitKind is different to the // string in the token. let s = symbol.as_str(); - let symbol = - if s.contains(&['\\', '\r']) { - let mut buf = String::with_capacity(s.len()); - let mut error = Ok(()); - unescape_literal(&s, Mode::Str, &mut |_, unescaped_char| { - match unescaped_char { - Ok(c) => buf.push(c), - Err(err) => { - if err.is_fatal() { - error = Err(LitError::LexerError); - } + let symbol = if s.contains(&['\\', '\r']) { + let mut buf = String::with_capacity(s.len()); + let mut error = Ok(()); + // Force-inlining here is aggressive but the closure is + // called on every char in the string, so it can be + // hot in programs with many long strings. + unescape_literal( + &s, + Mode::Str, + &mut #[inline(always)] + |_, unescaped_char| match unescaped_char { + Ok(c) => buf.push(c), + Err(err) => { + if err.is_fatal() { + error = Err(LitError::LexerError); } } - }); - error?; - Symbol::intern(&buf) - } else { - symbol - }; + }, + ); + error?; + Symbol::intern(&buf) + } else { + symbol + }; LitKind::Str(symbol, ast::StrStyle::Cooked) } token::StrRaw(n) => { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a8633336512..3ddc7fce1b7 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -444,8 +444,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ), ItemKind::MacroDef(MacroDef { ref body, macro_rules }) => { let body = P(self.lower_mac_args(body)); - - hir::ItemKind::Macro(ast::MacroDef { body, macro_rules }) + let macro_kind = self.resolver.decl_macro_kind(self.resolver.local_def_id(id)); + hir::ItemKind::Macro(ast::MacroDef { body, macro_rules }, macro_kind) } ItemKind::MacCall(..) => { panic!("`TyMac` should have been expanded by now") diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 0a59e3c2e3f..0156c5016ac 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -61,7 +61,7 @@ use rustc_session::lint::LintBuffer; use rustc_session::parse::feature_err; use rustc_session::utils::{FlattenNonterminals, NtToTokenstream}; use rustc_session::Session; -use rustc_span::hygiene::ExpnId; +use rustc_span::hygiene::{ExpnId, MacroKind}; use rustc_span::source_map::{respan, DesugaringKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -210,6 +210,8 @@ pub trait ResolverAstLowering { expn_id: ExpnId, span: Span, ) -> LocalDefId; + + fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind; } /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree, diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 8d6c8c24785..68b536da9f7 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -8,6 +8,7 @@ use rustc_errors::{struct_span_err, Applicability}; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; use rustc_macros::HashStable_Generic; use rustc_session::lint::builtin::UNEXPECTED_CFGS; +use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; use rustc_session::Session; use rustc_span::hygiene::Transparency; @@ -461,29 +462,37 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat true } MetaItemKind::NameValue(..) | MetaItemKind::Word => { - let name = cfg.ident().expect("multi-segment cfg predicate").name; + let ident = cfg.ident().expect("multi-segment cfg predicate"); + let name = ident.name; let value = cfg.value_str(); - if sess.check_config.names_checked && !sess.check_config.names_valid.contains(&name) - { - sess.buffer_lint( - UNEXPECTED_CFGS, - cfg.span, - CRATE_NODE_ID, - "unexpected `cfg` condition name", - ); - } - if let Some(val) = value { - if sess.check_config.values_checked.contains(&name) - && !sess.check_config.values_valid.contains(&(name, val)) - { - sess.buffer_lint( + if let Some(names_valid) = &sess.check_config.names_valid { + if !names_valid.contains(&name) { + sess.buffer_lint_with_diagnostic( UNEXPECTED_CFGS, cfg.span, CRATE_NODE_ID, - "unexpected `cfg` condition value", + "unexpected `cfg` condition name", + BuiltinLintDiagnostics::UnexpectedCfg(ident.span, name, None), ); } } + if let Some(value) = value { + if let Some(values) = &sess.check_config.values_valid.get(&name) { + if !values.contains(&value) { + sess.buffer_lint_with_diagnostic( + UNEXPECTED_CFGS, + cfg.span, + CRATE_NODE_ID, + "unexpected `cfg` condition value", + BuiltinLintDiagnostics::UnexpectedCfg( + cfg.name_value_literal_span().unwrap(), + name, + Some(value), + ), + ); + } + } + } sess.config.contains(&(name, value)) } } diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 7140cda8e4e..e2b6a48a9e8 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -1,9 +1,13 @@ -use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId}; +use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId, ErrorReported}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::{MultiSpan, Span}; impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { - crate fn cannot_move_when_borrowed(&self, span: Span, desc: &str) -> DiagnosticBuilder<'cx> { + crate fn cannot_move_when_borrowed( + &self, + span: Span, + desc: &str, + ) -> DiagnosticBuilder<'cx, ErrorReported> { struct_span_err!(self, span, E0505, "cannot move out of {} because it is borrowed", desc,) } @@ -13,7 +17,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { desc: &str, borrow_span: Span, borrow_desc: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let mut err = struct_span_err!( self, span, @@ -32,7 +36,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { span: Span, verb: &str, desc: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { struct_span_err!( self, span, @@ -51,7 +55,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { old_loan_span: Span, old_opt_via: &str, old_load_end_span: Option<Span>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) }; let mut err = struct_span_err!( @@ -99,7 +103,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { desc: &str, old_loan_span: Span, old_load_end_span: Option<Span>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let mut err = struct_span_err!( self, new_loan_span, @@ -132,7 +136,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { noun_old: &str, old_opt_via: &str, previous_end_span: Option<Span>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let mut err = struct_span_err!( self, new_loan_span, @@ -164,7 +168,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { old_opt_via: &str, previous_end_span: Option<Span>, second_borrow_desc: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let mut err = struct_span_err!( self, new_loan_span, @@ -200,7 +204,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { kind_old: &str, msg_old: &str, old_load_end_span: Option<Span>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) }; let mut err = struct_span_err!( @@ -243,7 +247,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { span: Span, borrow_span: Span, desc: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let mut err = struct_span_err!( self, span, @@ -262,12 +266,12 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { span: Span, desc: &str, is_arg: bool, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" }; struct_span_err!(self, span, E0384, "cannot assign {} {}", msg, desc) } - crate fn cannot_assign(&self, span: Span, desc: &str) -> DiagnosticBuilder<'cx> { + crate fn cannot_assign(&self, span: Span, desc: &str) -> DiagnosticBuilder<'cx, ErrorReported> { struct_span_err!(self, span, E0594, "cannot assign to {}", desc) } @@ -275,7 +279,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { &self, move_from_span: Span, move_from_desc: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc,) } @@ -287,7 +291,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { move_from_span: Span, ty: Ty<'_>, is_index: Option<bool>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let type_name = match (&ty.kind(), is_index) { (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array", (&ty::Slice(_), _) => "slice", @@ -309,7 +313,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { &self, move_from_span: Span, container_ty: Ty<'_>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let mut err = struct_span_err!( self, move_from_span, @@ -327,7 +331,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { verb: &str, optional_adverb_for_moved: &str, moved_path: Option<String>, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let moved_path = moved_path.map(|mp| format!(": `{}`", mp)).unwrap_or_default(); struct_span_err!( @@ -346,7 +350,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { span: Span, path: &str, reason: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,) } @@ -357,7 +361,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { immutable_place: &str, immutable_section: &str, action: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let mut err = struct_span_err!( self, mutate_span, @@ -376,7 +380,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { &self, span: Span, yield_span: Span, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let mut err = struct_span_err!( self, span, @@ -387,7 +391,10 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { err } - crate fn cannot_borrow_across_destructor(&self, borrow_span: Span) -> DiagnosticBuilder<'cx> { + crate fn cannot_borrow_across_destructor( + &self, + borrow_span: Span, + ) -> DiagnosticBuilder<'cx, ErrorReported> { struct_span_err!( self, borrow_span, @@ -400,7 +407,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { &self, span: Span, path: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { struct_span_err!(self, span, E0597, "{} does not live long enough", path,) } @@ -410,7 +417,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { return_kind: &str, reference_desc: &str, path_desc: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let mut err = struct_span_err!( self, span, @@ -435,7 +442,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { closure_kind: &str, borrowed_path: &str, capture_span: Span, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let mut err = struct_span_err!( self, closure_span, @@ -454,11 +461,14 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { crate fn thread_local_value_does_not_live_long_enough( &self, span: Span, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",) } - crate fn temporary_value_borrowed_for_too_long(&self, span: Span) -> DiagnosticBuilder<'cx> { + crate fn temporary_value_borrowed_for_too_long( + &self, + span: Span, + ) -> DiagnosticBuilder<'cx, ErrorReported> { struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",) } @@ -467,7 +477,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { sp: S, msg: &str, code: DiagnosticId, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { self.infcx.tcx.sess.struct_span_err_with_code(sp, msg, code) } } @@ -476,7 +486,7 @@ crate fn borrowed_data_escapes_closure<'tcx>( tcx: TyCtxt<'tcx>, escape_span: Span, escapes_from: &str, -) -> DiagnosticBuilder<'tcx> { +) -> DiagnosticBuilder<'tcx, ErrorReported> { struct_span_err!( tcx.sess, escape_span, diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 2a906e41b8c..3ef002bf740 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::DiagnosticBuilder; +use rustc_errors::{DiagnosticBuilder, ErrorReported}; use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError; use rustc_infer::infer::region_constraints::Constraint; @@ -120,7 +120,11 @@ impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::Custo trait TypeOpInfo<'tcx> { /// Returns an error to be reported if rerunning the type op fails to /// recover the error's cause. - fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>; + fn fallback_error( + &self, + tcx: TyCtxt<'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported>; fn base_universe(&self) -> ty::UniverseIndex; @@ -130,7 +134,7 @@ trait TypeOpInfo<'tcx> { cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, - ) -> Option<DiagnosticBuilder<'tcx>>; + ) -> Option<DiagnosticBuilder<'tcx, ErrorReported>>; fn report_error( &self, @@ -188,7 +192,11 @@ struct PredicateQuery<'tcx> { } impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { - fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn fallback_error( + &self, + tcx: TyCtxt<'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error"); err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate)); err @@ -204,7 +212,7 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, - ) -> Option<DiagnosticBuilder<'tcx>> { + ) -> Option<DiagnosticBuilder<'tcx, ErrorReported>> { tcx.infer_ctxt().enter_with_canonical( cause.span, &self.canonical_query, @@ -231,7 +239,11 @@ impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T> where T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx, { - fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn fallback_error( + &self, + tcx: TyCtxt<'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error"); err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value)); err @@ -247,7 +259,7 @@ where cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, - ) -> Option<DiagnosticBuilder<'tcx>> { + ) -> Option<DiagnosticBuilder<'tcx, ErrorReported>> { tcx.infer_ctxt().enter_with_canonical( cause.span, &self.canonical_query, @@ -288,7 +300,11 @@ struct AscribeUserTypeQuery<'tcx> { } impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { - fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn fallback_error( + &self, + tcx: TyCtxt<'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests, // and is only the fallback when the nice error fails. Consider improving this some more. tcx.sess.struct_span_err(span, "higher-ranked lifetime error") @@ -304,7 +320,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, - ) -> Option<DiagnosticBuilder<'tcx>> { + ) -> Option<DiagnosticBuilder<'tcx, ErrorReported>> { tcx.infer_ctxt().enter_with_canonical( cause.span, &self.canonical_query, @@ -329,7 +345,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( infcx: &InferCtxt<'_, 'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, -) -> Option<DiagnosticBuilder<'tcx>> { +) -> Option<DiagnosticBuilder<'tcx, ErrorReported>> { let tcx = infcx.tcx; // We generally shouldn't have errors here because the query was diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index baa59efbf8d..cd1f73d5298 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1,7 +1,7 @@ use either::Either; use rustc_const_eval::util::{CallDesugaringKind, CallKind}; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; @@ -507,7 +507,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, (place, _span): (Place<'tcx>, Span), borrow: &BorrowData<'tcx>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let borrow_spans = self.retrieve_borrow_spans(borrow); let borrow_span = borrow_spans.args_or_use(); @@ -554,7 +554,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (place, span): (Place<'tcx>, Span), gen_borrow_kind: BorrowKind, issued_borrow: &BorrowData<'tcx>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let issued_spans = self.retrieve_borrow_spans(issued_borrow); let issued_span = issued_spans.args_or_use(); @@ -782,7 +782,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { #[instrument(level = "debug", skip(self, err))] fn suggest_using_local_if_applicable( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, location: Location, (place, span): (Place<'tcx>, Span), gen_borrow_kind: BorrowKind, @@ -855,7 +855,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn suggest_split_at_mut_if_applicable( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, place: Place<'tcx>, borrowed_place: Place<'tcx>, ) { @@ -1120,7 +1120,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { drop_span: Span, borrow_spans: UseSpans<'tcx>, explanation: BorrowExplanation, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { debug!( "report_local_value_does_not_live_long_enough(\ {:?}, {:?}, {:?}, {:?}, {:?}\ @@ -1298,7 +1298,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut self, drop_span: Span, borrow_span: Span, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { debug!( "report_thread_local_value_does_not_live_long_enough(\ {:?}, {:?}\ @@ -1325,7 +1325,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_spans: UseSpans<'tcx>, proper_span: Span, explanation: BorrowExplanation, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { debug!( "report_temporary_value_does_not_live_long_enough(\ {:?}, {:?}, {:?}, {:?}\ @@ -1384,7 +1384,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return_span: Span, category: ConstraintCategory, opt_place_desc: Option<&String>, - ) -> Option<DiagnosticBuilder<'cx>> { + ) -> Option<DiagnosticBuilder<'cx, ErrorReported>> { let return_kind = match category { ConstraintCategory::Return(_) => "return", ConstraintCategory::Yield => "yield", @@ -1483,7 +1483,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { category: ConstraintCategory, constraint_span: Span, captured_var: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let tcx = self.infcx.tcx; let args_span = use_span.args_or_use(); @@ -1560,7 +1560,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { upvar_span: Span, upvar_name: &str, escape_span: Span, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'cx, ErrorReported> { let tcx = self.infcx.tcx; let (_, escapes_from) = tcx.article_and_description(self.mir_def_id().to_def_id()); @@ -1835,7 +1835,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.buffer_error(err); } - fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) { + fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) { let tcx = self.infcx.tcx; if let ( Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }), @@ -2362,11 +2362,7 @@ enum AnnotatedBorrowFnSignature<'tcx> { impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { /// Annotate the provided diagnostic with information about borrow from the fn signature that /// helps explain. - pub(crate) fn emit( - &self, - cx: &mut MirBorrowckCtxt<'_, 'tcx>, - diag: &mut DiagnosticBuilder<'_>, - ) -> String { + pub(crate) fn emit(&self, cx: &mut MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diagnostic) -> String { match self { &AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => { diag.span_label( diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index b1e5a211cf1..da6610c002e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -3,7 +3,7 @@ use std::collections::VecDeque; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_index::vec::IndexVec; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::{ @@ -60,7 +60,7 @@ impl BorrowExplanation { tcx: TyCtxt<'tcx>, body: &Body<'tcx>, local_names: &IndexVec<Local, Option<Symbol>>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, borrow_desc: &str, borrow_span: Option<Span>, multiple_borrow_span: Option<(Span, Span)>, @@ -275,7 +275,7 @@ impl BorrowExplanation { } pub(crate) fn add_lifetime_bound_suggestion_to_diagnostic( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, category: &ConstraintCategory, span: Span, region_name: &RegionName, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 7f94e357f37..754856043b3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1,7 +1,7 @@ //! Borrow checker diagnostics. use rustc_const_eval::util::call_kind; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; @@ -57,7 +57,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self, location: Location, place: PlaceRef<'tcx>, - diag: &mut DiagnosticBuilder<'_>, + diag: &mut Diagnostic, ) { debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place); let mut target = place.local_or_deref_local(); @@ -409,7 +409,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Add a note that a type does not implement `Copy` pub(super) fn note_type_does_not_implement_copy( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, place_desc: &str, ty: Ty<'tcx>, span: Option<Span>, @@ -609,11 +609,7 @@ impl UseSpans<'_> { } // Add a span label to the arguments of the closure, if it exists. - pub(super) fn args_span_label( - self, - err: &mut DiagnosticBuilder<'_>, - message: impl Into<String>, - ) { + pub(super) fn args_span_label(self, err: &mut Diagnostic, message: impl Into<String>) { if let UseSpans::ClosureUse { args_span, .. } = self { err.span_label(args_span, message); } @@ -621,11 +617,7 @@ impl UseSpans<'_> { // Add a span label to the use of the captured variable, if it exists. // only adds label to the `path_span` - pub(super) fn var_span_label_path_only( - self, - err: &mut DiagnosticBuilder<'_>, - message: impl Into<String>, - ) { + pub(super) fn var_span_label_path_only(self, err: &mut Diagnostic, message: impl Into<String>) { if let UseSpans::ClosureUse { path_span, .. } = self { err.span_label(path_span, message); } @@ -634,7 +626,7 @@ impl UseSpans<'_> { // Add a span label to the use of the captured variable, if it exists. pub(super) fn var_span_label( self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, message: impl Into<String>, kind_desc: impl Into<String>, ) { diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index d4f238ff71f..66f4c28a36d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -1,5 +1,5 @@ use rustc_const_eval::util::CallDesugaringKind; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::*; use rustc_middle::ty; @@ -271,7 +271,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { &mut self, place: Place<'tcx>, span: Span, - ) -> DiagnosticBuilder<'a> { + ) -> DiagnosticBuilder<'a, ErrorReported> { let description = if place.projection.len() == 1 { format!("static item {}", self.describe_any_place(place.as_ref())) } else { @@ -293,7 +293,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { deref_target_place: Place<'tcx>, span: Span, use_spans: Option<UseSpans<'tcx>>, - ) -> DiagnosticBuilder<'a> { + ) -> DiagnosticBuilder<'a, ErrorReported> { // Inspect the type of the content behind the // borrow to provide feedback about why this // was a move rather than a copy. @@ -441,12 +441,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err } - fn add_move_hints( - &self, - error: GroupedMoveError<'tcx>, - err: &mut DiagnosticBuilder<'a>, - span: Span, - ) { + fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diagnostic, span: Span) { match error { GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => { if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { @@ -505,7 +500,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - fn add_move_error_suggestions(&self, err: &mut DiagnosticBuilder<'a>, binds_to: &[Local]) { + fn add_move_error_suggestions(&self, err: &mut Diagnostic, binds_to: &[Local]) { let mut suggestions: Vec<(Span, &str, String)> = Vec::new(); for local in binds_to { let bind_to = &self.body.local_decls[*local]; @@ -541,7 +536,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - fn add_move_error_details(&self, err: &mut DiagnosticBuilder<'a>, binds_to: &[Local]) { + fn add_move_error_details(&self, err: &mut Diagnostic, binds_to: &[Local]) { for (j, local) in binds_to.iter().enumerate() { let bind_to = &self.body.local_decls[*local]; let binding_span = bind_to.source_info.span; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 7d0dde53c2b..2c9bd8ea96e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -17,7 +17,7 @@ use rustc_span::{BytePos, Span}; use crate::diagnostics::BorrowedContentSource; use crate::MirBorrowckCtxt; use rustc_const_eval::util::collect_writes::FindAssignments; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub(crate) enum AccessKind { @@ -689,7 +689,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { tcx: TyCtxt<'_>, id: &hir::def_id::DefId, the_place_err: PlaceRef<'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, ) { let closure_local_def_id = id.expect_local(); let tables = tcx.typeck(closure_local_def_id); @@ -754,7 +754,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Attempt to search similar mutable associated items for suggestion. // In the future, attempt in all path but initially for RHS of for_loop - fn suggest_similar_mut_method_for_for_loop(&self, err: &mut DiagnosticBuilder<'_>) { + fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diagnostic) { use hir::{ BodyId, Expr, ExprKind::{Block, Call, DropTemps, Match, MethodCall}, @@ -843,7 +843,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected. - fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) { + fn expected_fn_found_fn_mut_call(&self, err: &mut Diagnostic, sp: Span, act: &str) { err.span_label(sp, format!("cannot {}", act)); let hir = self.infcx.tcx.hir(); diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index 21f00af5c0c..de50f907eff 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -2,7 +2,7 @@ //! outlives constraints. use rustc_data_structures::fx::FxHashSet; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::Diagnostic; use rustc_middle::ty::RegionVid; use smallvec::SmallVec; use std::collections::BTreeMap; @@ -162,7 +162,7 @@ impl OutlivesSuggestionBuilder { &mut self, mbcx: &MirBorrowckCtxt<'_, '_>, errci: &ErrorConstraintInfo, - diag: &mut DiagnosticBuilder<'_>, + diag: &mut Diagnostic, ) { // Emit an intermediate note. let fr_name = self.region_vid_to_name(mbcx, errci.fr); @@ -256,6 +256,6 @@ impl OutlivesSuggestionBuilder { diag.sort_span = mir_span.shrink_to_hi(); // Buffer the diagnostic - mbcx.buffer_error(diag); + mbcx.buffer_non_error_diag(diag); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index e6a323d676e..64f05f6004f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1,6 +1,6 @@ //! Error reporting machinery for lifetime errors. -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported}; use rustc_infer::infer::{ error_reporting::nice_region_error::NiceRegionError, error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin, @@ -392,7 +392,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { &self, errci: &ErrorConstraintInfo, kind: ReturnConstraint, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let ErrorConstraintInfo { outlived_fr, span, .. } = errci; let mut diag = self @@ -469,7 +469,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// LL | ref_obj(x) /// | ^^^^^^^^^^ `x` escapes the function body here /// ``` - fn report_escaping_data_error(&self, errci: &ErrorConstraintInfo) -> DiagnosticBuilder<'tcx> { + fn report_escaping_data_error( + &self, + errci: &ErrorConstraintInfo, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let ErrorConstraintInfo { span, category, .. } = errci; let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region( @@ -570,7 +573,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it /// | is returning data with lifetime `'b` /// ``` - fn report_general_error(&self, errci: &ErrorConstraintInfo) -> DiagnosticBuilder<'tcx> { + fn report_general_error( + &self, + errci: &ErrorConstraintInfo, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let ErrorConstraintInfo { fr, fr_is_local, @@ -632,7 +638,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// ``` fn add_static_impl_trait_suggestion( &self, - diag: &mut DiagnosticBuilder<'tcx>, + diag: &mut Diagnostic, fr: RegionVid, // We need to pass `fr_name` - computing it again will label it twice. fr_name: RegionName, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 5d1d291d3b4..c9395492c9e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -1,7 +1,7 @@ use std::fmt::{self, Display}; use std::iter; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::print::RegionHighlightMode; @@ -98,7 +98,7 @@ impl RegionName { } } - crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) { + crate fn highlight_region_name(&self, diag: &mut Diagnostic) { match &self.source { RegionNameSource::NamedFreeRegion(span) | RegionNameSource::NamedEarlyBoundRegion(span) => { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 753eed53068..590c5799ff6 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -379,7 +379,7 @@ fn do_mir_borrowck<'a, 'tcx>( // Convert any reservation warnings into lints. let reservation_warnings = mem::take(&mut mbcx.reservation_warnings); for (_, (place, span, location, bk, borrow)) in reservation_warnings { - let mut initial_diag = mbcx.report_conflicting_borrow(location, (place, span), bk, &borrow); + let initial_diag = mbcx.report_conflicting_borrow(location, (place, span), bk, &borrow); let scope = mbcx.body.source_info(location).scope; let lint_root = match &mbcx.body.source_scopes[scope].local_data { @@ -398,7 +398,7 @@ fn do_mir_borrowck<'a, 'tcx>( diag.message = initial_diag.styled_message().clone(); diag.span = initial_diag.span.clone(); - mbcx.buffer_error(diag); + mbcx.buffer_non_error_diag(diag); }, ); initial_diag.cancel(); @@ -2293,8 +2293,8 @@ mod error { /// when errors in the map are being re-added to the error buffer so that errors with the /// same primary span come out in a consistent order. buffered_move_errors: - BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>, - /// Errors to be reported buffer + BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorReported>)>, + /// Diagnostics to be reported buffer. buffered: Vec<Diagnostic>, /// Set to Some if we emit an error during borrowck tainted_by_errors: Option<ErrorReported>, @@ -2309,27 +2309,37 @@ mod error { } } - pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) { + // FIXME(eddyb) this is a suboptimal API because `tainted_by_errors` is + // set before any emission actually happens (weakening the guarantee). + pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_, ErrorReported>) { self.tainted_by_errors = Some(ErrorReported {}); t.buffer(&mut self.buffered); } + pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) { + t.buffer(&mut self.buffered); + } + pub fn set_tainted_by_errors(&mut self) { self.tainted_by_errors = Some(ErrorReported {}); } } impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) { + pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_, ErrorReported>) { self.errors.buffer_error(t); } + pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) { + self.errors.buffer_non_error_diag(t); + } + pub fn buffer_move_error( &mut self, move_out_indices: Vec<MoveOutIndex>, - place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>), + place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorReported>), ) -> bool { - if let Some((_, mut diag)) = + if let Some((_, diag)) = self.errors.buffered_move_errors.insert(move_out_indices, place_and_err) { // Cancel the old diagnostic so we don't ICE @@ -2365,7 +2375,7 @@ mod error { pub fn has_move_error( &self, move_out_indices: &[MoveOutIndex], - ) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx>)> { + ) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx, ErrorReported>)> { self.errors.buffered_move_errors.get(move_out_indices) } } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index a16bdf28673..a2736fd1156 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -417,7 +417,7 @@ pub(super) fn dump_annotation<'a, 'tcx>( err.note(&format!("Inferred opaque type values:\n{:#?}", opaque_type_values)); } - errors.buffer_error(err); + errors.buffer_non_error_diag(err); } fn for_each_region_constraint( diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index b99fb00599e..3f0ce7dea00 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -5,6 +5,7 @@ use rustc_data_structures::binary_search_util; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::scc::Sccs; +use rustc_errors::Diagnostic; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_hir::CRATE_HIR_ID; use rustc_index::vec::IndexVec; @@ -510,7 +511,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`. - crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut rustc_errors::DiagnosticBuilder<'_>) { + crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) { self.universal_regions.annotate(tcx, err) } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index d21a9d86e5b..478dbe31fba 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -14,7 +14,7 @@ use either::Either; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; @@ -336,7 +336,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// that this region imposes on others. The methods in this file /// handle the part about dumping the inference context internal /// state. - crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_>) { + crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) { match self.defining_ty { DefiningTy::Closure(def_id, substs) => { err.note(&format!( diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index ac37c4973d8..57ef46475dd 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -3,7 +3,7 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, PResult}; use rustc_expand::base::{self, *}; use rustc_parse::parser::Parser; use rustc_parse_format as parse; @@ -30,7 +30,7 @@ fn parse_args<'a>( sp: Span, tts: TokenStream, is_global_asm: bool, -) -> Result<AsmArgs, DiagnosticBuilder<'a>> { +) -> PResult<'a, AsmArgs> { let mut p = ecx.new_parser_from_tts(tts); let sess = &ecx.sess.parse_sess; parse_asm_args(&mut p, sess, sp, is_global_asm) @@ -43,7 +43,7 @@ pub fn parse_asm_args<'a>( sess: &'a ParseSess, sp: Span, is_global_asm: bool, -) -> Result<AsmArgs, DiagnosticBuilder<'a>> { +) -> PResult<'a, AsmArgs> { let diag = &sess.span_diagnostic; if p.token == token::Eof { @@ -390,7 +390,7 @@ fn parse_options<'a>( p: &mut Parser<'a>, args: &mut AsmArgs, is_global_asm: bool, -) -> Result<(), DiagnosticBuilder<'a>> { +) -> PResult<'a, ()> { let span_start = p.prev_token.span; p.expect(&token::OpenDelim(token::DelimToken::Paren))?; @@ -431,10 +431,7 @@ fn parse_options<'a>( Ok(()) } -fn parse_clobber_abi<'a>( - p: &mut Parser<'a>, - args: &mut AsmArgs, -) -> Result<(), DiagnosticBuilder<'a>> { +fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, ()> { let span_start = p.prev_token.span; p.expect(&token::OpenDelim(token::DelimToken::Paren))?; @@ -501,7 +498,7 @@ fn parse_clobber_abi<'a>( fn parse_reg<'a>( p: &mut Parser<'a>, explicit_reg: &mut bool, -) -> Result<ast::InlineAsmRegOrRegClass, DiagnosticBuilder<'a>> { +) -> PResult<'a, ast::InlineAsmRegOrRegClass> { p.expect(&token::OpenDelim(token::DelimToken::Paren))?; let result = match p.token.uninterpolate().kind { token::Ident(name, false) => ast::InlineAsmRegOrRegClass::RegClass(name), diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 9a45dec55f3..a984980dea9 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -4,7 +4,7 @@ use rustc_ast::token; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, PResult}; use rustc_expand::base::*; use rustc_parse::parser::Parser; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -83,11 +83,7 @@ struct Assert { custom_message: Option<TokenStream>, } -fn parse_assert<'a>( - cx: &mut ExtCtxt<'a>, - sp: Span, - stream: TokenStream, -) -> Result<Assert, DiagnosticBuilder<'a>> { +fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> { let mut parser = cx.new_parser_from_tts(stream); if parser.token == token::Eof { diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 4c00162b556..1e1cf917c60 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -6,7 +6,7 @@ use rustc_ast as ast; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_attr as attr; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::PResult; use rustc_expand::base::{self, *}; use rustc_span::Span; @@ -29,11 +29,7 @@ pub fn expand_cfg( } } -fn parse_cfg<'a>( - cx: &mut ExtCtxt<'a>, - sp: Span, - tts: TokenStream, -) -> Result<ast::MetaItem, DiagnosticBuilder<'a>> { +fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 6141d00f697..31213412d45 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -7,7 +7,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{token, BlockCheckMode, UnsafeSource}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{pluralize, Applicability, DiagnosticBuilder}; +use rustc_errors::{pluralize, Applicability, PResult}; use rustc_expand::base::{self, *}; use rustc_parse_format as parse; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -130,7 +130,7 @@ fn parse_args<'a>( ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream, -) -> Result<(P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, usize>), DiagnosticBuilder<'a>> { +) -> PResult<'a, (P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, usize>)> { let mut args = Vec::<P<ast::Expr>>::new(); let mut names = FxHashMap::<Symbol, usize>::default(); diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 418729e7843..7ee0fb9b817 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -376,9 +376,13 @@ fn get_test_runner( match &*meta_list { [single] => match single.meta_item() { Some(meta_item) if meta_item.is_word() => return Some(meta_item.path.clone()), - _ => sd.struct_span_err(span, "`test_runner` argument must be a path").emit(), + _ => { + sd.struct_span_err(span, "`test_runner` argument must be a path").emit(); + } }, - _ => sd.struct_span_err(span, "`#![test_runner(..)]` accepts exactly 1 argument").emit(), + _ => { + sd.struct_span_err(span, "`#![test_runner(..)]` accepts exactly 1 argument").emit(); + } } None } diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 9ce727279c2..2f71a70a449 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -51,7 +51,10 @@ pub(crate) fn maybe_create_entry_wrapper( // late-bound regions, since late-bound // regions must appear in the argument // listing. - let main_ret_ty = tcx.erase_regions(main_ret_ty.no_bound_vars().unwrap()); + let main_ret_ty = tcx.normalize_erasing_regions( + ty::ParamEnv::reveal_all(), + main_ret_ty.no_bound_vars().unwrap(), + ); let cmain_sig = Signature { params: vec![ diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 4ca92b3efe0..d515502d445 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -449,7 +449,10 @@ fn pointer_or_reference_metadata<'ll, 'tcx>( // This is a thin pointer. Create a regular pointer type and give it the correct name. debug_assert_eq!( (thin_pointer_size, thin_pointer_align), - cx.size_and_align_of(ptr_type) + cx.size_and_align_of(ptr_type), + "ptr_type={}, pointee_type={}", + ptr_type, + pointee_type, ); unsafe { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index acd032a7dc6..fa75463067f 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -4,9 +4,9 @@ use super::namespace::item_namespace; use super::CrateDebugContext; use rustc_hir::def_id::DefId; -use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, DefIdTree, Ty}; -use rustc_target::abi::Variants; +use tracing::trace; use crate::common::CodegenCx; use crate::llvm; @@ -63,30 +63,26 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, pointee_ty: Ty<'tcx>, ) -> Option<FatPtrKind> { - let layout = cx.layout_of(pointee_ty); + let pointee_tail_ty = cx.tcx.struct_tail_erasing_lifetimes(pointee_ty, cx.param_env()); + let layout = cx.layout_of(pointee_tail_ty); + trace!( + "fat_pointer_kind: {:?} has layout {:?} (is_unsized? {})", + pointee_tail_ty, + layout, + layout.is_unsized() + ); if !layout.is_unsized() { return None; } - match *pointee_ty.kind() { + match *pointee_tail_ty.kind() { ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice), ty::Dynamic(..) => Some(FatPtrKind::Dyn), - ty::Adt(..) | ty::Tuple(..) if matches!(layout.variants, Variants::Single { .. }) => { - let last_field_index = layout.fields.count() - 1; - debug_assert!( - (0..last_field_index) - .all(|field_index| { !layout.field(cx, field_index).is_unsized() }) - ); - - let unsized_field = layout.field(cx, last_field_index); - debug_assert!(unsized_field.is_unsized()); - fat_pointer_kind(cx, unsized_field.ty) - } ty::Foreign(_) => { // Assert that pointers to foreign types really are thin: debug_assert_eq!( - cx.size_of(cx.tcx.mk_imm_ptr(pointee_ty)), + cx.size_of(cx.tcx.mk_imm_ptr(pointee_tail_ty)), cx.size_of(cx.tcx.mk_imm_ptr(cx.tcx.types.u8)) ); None @@ -94,7 +90,10 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>( _ => { // For all other pointee types we should already have returned None // at the beginning of the function. - panic!("fat_pointer_kind() - Encountered unexpected `pointee_ty`: {:?}", pointee_ty) + panic!( + "fat_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {:?}", + pointee_tail_ty + ) } } } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index f6fddbb509d..55ea0c4d727 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1709,7 +1709,7 @@ impl Emitter for SharedEmitter { drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { msg: diag.message(), code: diag.code.clone(), - lvl: diag.level, + lvl: diag.level(), }))); for child in &diag.children { drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { @@ -1753,7 +1753,7 @@ impl SharedEmitterMain { let msg = msg.strip_prefix("error: ").unwrap_or(&msg); let mut err = match level { - Level::Error { lint: false } => sess.struct_err(&msg), + Level::Error { lint: false } => sess.struct_err(&msg).forget_guarantee(), Level::Warning => sess.struct_warn(&msg), Level::Note => sess.struct_note_without_error(&msg), _ => bug!("Invalid inline asm diagnostic level"), diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index ed6c156547e..11f32d92e44 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -407,7 +407,10 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // late-bound regions, since late-bound // regions must appear in the argument // listing. - let main_ret_ty = cx.tcx().erase_regions(main_ret_ty.no_bound_vars().unwrap()); + let main_ret_ty = cx.tcx().normalize_erasing_regions( + ty::ParamEnv::reveal_all(), + main_ret_ty.no_bound_vars().unwrap(), + ); let Some(llfn) = cx.declare_c_main(llfty) else { // FIXME: We should be smart and show a better diagnostic here. diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 89a0f8245e5..3bd092263c1 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -1,7 +1,7 @@ use std::error::Error; use std::fmt; -use rustc_errors::{DiagnosticBuilder, ErrorReported}; +use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_middle::mir::AssertKind; use rustc_middle::ty::{layout::LayoutError, query::TyCtxtAt, ConstInt}; @@ -94,13 +94,13 @@ impl<'tcx> ConstEvalErr<'tcx> { &self, tcx: TyCtxtAt<'tcx>, message: &str, - emit: impl FnOnce(DiagnosticBuilder<'_>), + decorate: impl FnOnce(&mut Diagnostic), ) -> ErrorHandled { - self.struct_generic(tcx, message, emit, None) + self.struct_generic(tcx, message, decorate, None) } pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled { - self.struct_error(tcx, message, |mut e| e.emit()) + self.struct_error(tcx, message, |_| {}) } pub fn report_as_lint( @@ -113,7 +113,7 @@ impl<'tcx> ConstEvalErr<'tcx> { self.struct_generic( tcx, message, - |mut lint: DiagnosticBuilder<'_>| { + |lint: &mut Diagnostic| { // Apply the span. if let Some(span) = span { let primary_spans = lint.span.primary_spans().to_vec(); @@ -127,7 +127,6 @@ impl<'tcx> ConstEvalErr<'tcx> { } } } - lint.emit(); }, Some(lint_root), ) @@ -136,9 +135,8 @@ impl<'tcx> ConstEvalErr<'tcx> { /// Create a diagnostic for this const eval error. /// /// Sets the message passed in via `message` and adds span labels with detailed error - /// information before handing control back to `emit` to do any final processing. - /// It's the caller's responsibility to call emit(), stash(), etc. within the `emit` - /// function to dispose of the diagnostic properly. + /// information before handing control back to `decorate` to do any final annotations, + /// after which the diagnostic is emitted. /// /// If `lint_root.is_some()` report it as a lint, else report it as a hard error. /// (Except that for some errors, we ignore all that -- see `must_error` below.) @@ -146,10 +144,10 @@ impl<'tcx> ConstEvalErr<'tcx> { &self, tcx: TyCtxtAt<'tcx>, message: &str, - emit: impl FnOnce(DiagnosticBuilder<'_>), + decorate: impl FnOnce(&mut Diagnostic), lint_root: Option<hir::HirId>, ) -> ErrorHandled { - let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| { + let finish = |err: &mut Diagnostic, span_msg: Option<String>| { trace!("reporting const eval failure at {:?}", self.span); if let Some(span_msg) = span_msg { err.span_label(self.span, span_msg); @@ -188,8 +186,8 @@ impl<'tcx> ConstEvalErr<'tcx> { } flush_last_line(last_frame, times); } - // Let the caller finish the job. - emit(err) + // Let the caller attach any additional information it wants. + decorate(err); }; // Special handling for certain errors @@ -206,8 +204,9 @@ impl<'tcx> ConstEvalErr<'tcx> { // The `message` makes little sense here, this is a more serious error than the // caller thinks anyway. // See <https://github.com/rust-lang/rust/pull/63152>. - finish(struct_error(tcx, &self.error.to_string()), None); - return ErrorHandled::Reported(ErrorReported); + let mut err = struct_error(tcx, &self.error.to_string()); + finish(&mut err, None); + return ErrorHandled::Reported(err.emit()); } _ => {} }; @@ -223,13 +222,18 @@ impl<'tcx> ConstEvalErr<'tcx> { rustc_session::lint::builtin::CONST_ERR, hir_id, tcx.span, - |lint| finish(lint.build(message), Some(err_msg)), + |lint| { + let mut lint = lint.build(message); + finish(&mut lint, Some(err_msg)); + lint.emit(); + }, ); ErrorHandled::Linted } else { // Report as hard error. - finish(struct_error(tcx, message), Some(err_msg)); - ErrorHandled::Reported(ErrorReported) + let mut err = struct_error(tcx, message); + finish(&mut err, Some(err_msg)); + ErrorHandled::Reported(err.emit()) } } } diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 533c32f807d..dad57274104 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -361,7 +361,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( Err(err.struct_error( ecx.tcx, "it is undefined behavior to use this value", - |mut diag| { + |diag| { diag.note(note_on_undefined_behavior_error()); diag.note(&format!( "the raw bytes of the constant ({}", @@ -370,7 +370,6 @@ pub fn eval_to_allocation_raw_provider<'tcx>( ecx.tcx.global_alloc(alloc_id).unwrap_memory() ) )); - diag.emit(); }, )) } else { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 888c4b997dc..5738b38d443 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -1,6 +1,6 @@ //! Concrete error types for all operations which may be invalid in a certain const context. -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; @@ -47,7 +47,11 @@ pub trait NonConstOp<'tcx>: std::fmt::Debug { DiagnosticImportance::Primary } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>; + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported>; } #[derive(Debug)] @@ -61,7 +65,11 @@ impl<'tcx> NonConstOp<'tcx> for FloatingPointOp { } } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_fn_floating_point_arithmetic, @@ -75,7 +83,11 @@ impl<'tcx> NonConstOp<'tcx> for FloatingPointOp { #[derive(Debug)] pub struct FnCallIndirect; impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn") } } @@ -91,11 +103,15 @@ pub struct FnCallNonConst<'tcx> { } impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + _: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let FnCallNonConst { caller, callee, substs, span, from_hir_call } = *self; let ConstCx { tcx, param_env, .. } = *ccx; - let diag_trait = |mut err, self_ty: Ty<'_>, trait_id| { + let diag_trait = |err, self_ty: Ty<'_>, trait_id| { let trait_ref = TraitRef::from_method(tcx, trait_id, substs); match self_ty.kind() { @@ -115,7 +131,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { suggest_constraining_type_param( tcx, generics, - &mut err, + err, ¶m_ty.name.as_str(), &constraint, None, @@ -146,8 +162,6 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { } _ => {} } - - err }; let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None); @@ -162,7 +176,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { }; } - let err = match kind { + let mut err = match kind { CallDesugaringKind::ForLoopIntoIter => { error!("cannot convert `{}` into an iterator in {}s") } @@ -177,7 +191,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { } }; - diag_trait(err, self_ty, kind.trait_def_id(tcx)) + diag_trait(&mut err, self_ty, kind.trait_def_id(tcx)); + err } CallKind::FnCall { fn_trait_id, self_ty } => { let mut err = struct_span_err!( @@ -212,7 +227,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { _ => {} } - diag_trait(err, self_ty, fn_trait_id) + diag_trait(&mut err, self_ty, fn_trait_id); + err } CallKind::Operator { trait_id, self_ty, .. } => { let mut err = struct_span_err!( @@ -262,7 +278,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { } } - diag_trait(err, self_ty, trait_id) + diag_trait(&mut err, self_ty, trait_id); + err } CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => { let mut err = struct_span_err!( @@ -281,7 +298,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { err.span_note(deref_target, "deref defined here"); } - diag_trait(err, self_ty, tcx.lang_items().deref_trait().unwrap()) + diag_trait(&mut err, self_ty, tcx.lang_items().deref_trait().unwrap()); + err } _ => struct_span_err!( ccx.tcx.sess, @@ -310,7 +328,11 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { pub struct FnCallUnstable(pub DefId, pub Option<Symbol>); impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let FnCallUnstable(def_id, feature) = *self; let mut err = ccx.tcx.sess.struct_span_err( @@ -344,7 +366,11 @@ impl<'tcx> NonConstOp<'tcx> for FnPtrCast { } } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_fn_fn_ptr_basics, @@ -365,7 +391,11 @@ impl<'tcx> NonConstOp<'tcx> for Generator { } } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind()); if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 { feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg) @@ -378,7 +408,11 @@ impl<'tcx> NonConstOp<'tcx> for Generator { #[derive(Debug)] pub struct HeapAllocation; impl<'tcx> NonConstOp<'tcx> for HeapAllocation { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let mut err = struct_span_err!( ccx.tcx.sess, span, @@ -402,7 +436,11 @@ impl<'tcx> NonConstOp<'tcx> for HeapAllocation { #[derive(Debug)] pub struct InlineAsm; impl<'tcx> NonConstOp<'tcx> for InlineAsm { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { struct_span_err!( ccx.tcx.sess, span, @@ -418,7 +456,11 @@ pub struct LiveDrop { pub dropped_at: Option<Span>, } impl<'tcx> NonConstOp<'tcx> for LiveDrop { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let mut err = struct_span_err!( ccx.tcx.sess, span, @@ -446,7 +488,11 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { // not additionally emit a feature gate error if activating the feature gate won't work. DiagnosticImportance::Secondary } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_refs_to_cell, @@ -462,7 +508,11 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { /// it in the future for static items. pub struct CellBorrow; impl<'tcx> NonConstOp<'tcx> for CellBorrow { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let mut err = struct_span_err!( ccx.tcx.sess, span, @@ -509,7 +559,11 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow { DiagnosticImportance::Secondary } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let raw = match self.0 { hir::BorrowKind::Raw => "raw ", hir::BorrowKind::Ref => "", @@ -548,7 +602,11 @@ impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow { Status::Unstable(sym::const_mut_refs) } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let raw = match self.0 { hir::BorrowKind::Raw => "raw ", hir::BorrowKind::Ref => "", @@ -575,7 +633,11 @@ impl<'tcx> NonConstOp<'tcx> for MutDeref { DiagnosticImportance::Secondary } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_mut_refs, @@ -589,7 +651,11 @@ impl<'tcx> NonConstOp<'tcx> for MutDeref { #[derive(Debug)] pub struct PanicNonStr; impl<'tcx> NonConstOp<'tcx> for PanicNonStr { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { ccx.tcx.sess.struct_span_err( span, "argument to `panic!()` in a const context must have type `&str`", @@ -603,7 +669,11 @@ impl<'tcx> NonConstOp<'tcx> for PanicNonStr { #[derive(Debug)] pub struct RawPtrComparison; impl<'tcx> NonConstOp<'tcx> for RawPtrComparison { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let mut err = ccx .tcx .sess @@ -623,7 +693,11 @@ impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref { Status::Unstable(sym::const_mut_refs) } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_mut_refs, @@ -639,7 +713,11 @@ impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref { #[derive(Debug)] pub struct RawPtrToIntCast; impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let mut err = ccx .tcx .sess @@ -664,7 +742,11 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess { } } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let mut err = struct_span_err!( ccx.tcx.sess, span, @@ -690,7 +772,11 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess { #[derive(Debug)] pub struct ThreadLocalAccess; impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess { - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { struct_span_err!( ccx.tcx.sess, span, @@ -721,7 +807,11 @@ pub mod ty { } } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_mut_refs, @@ -751,7 +841,11 @@ pub mod ty { } } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_fn_fn_ptr_basics, @@ -768,7 +862,11 @@ pub mod ty { Status::Unstable(sym::const_impl_trait) } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_impl_trait, @@ -798,7 +896,11 @@ pub mod ty { } } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let mut err = feature_err( &ccx.tcx.sess.parse_sess, sym::const_fn_trait_bound, @@ -837,7 +939,11 @@ pub mod ty { } } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let mut err = feature_err( &ccx.tcx.sess.parse_sess, sym::const_fn_trait_bound, @@ -864,7 +970,11 @@ pub mod ty { Status::Unstable(sym::const_trait_bound_opt_out) } - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + fn build_error( + &self, + ccx: &ConstCx<'_, 'tcx>, + span: Span, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { feature_err( &ccx.tcx.sess.parse_sess, sym::const_trait_bound_opt_out, diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 9db8f751390..7d7ab1ed4e5 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -66,12 +66,14 @@ fn source_string(file: Lrc<SourceFile>, line: &Line) -> String { /// Maps `Diagnostic::Level` to `snippet::AnnotationType` fn annotation_type_for_level(level: Level) -> AnnotationType { match level { - Level::Bug | Level::Fatal | Level::Error { .. } => AnnotationType::Error, + Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error { .. } => { + AnnotationType::Error + } Level::Warning => AnnotationType::Warning, Level::Note => AnnotationType::Note, Level::Help => AnnotationType::Help, - // FIXME(#59346): Not sure how to map these two levels - Level::Cancelled | Level::FailureNote => AnnotationType::Error, + // FIXME(#59346): Not sure how to map this level + Level::FailureNote => AnnotationType::Error, Level::Allow => panic!("Should not call with Allow"), } } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 8cfecafd20c..6d6ada86428 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -19,7 +19,10 @@ pub struct SuggestionsDisabled; #[must_use] #[derive(Clone, Debug, Encodable, Decodable)] pub struct Diagnostic { - pub level: Level, + // NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes, + // outside of what methods in this crate themselves allow. + crate level: Level, + pub message: Vec<(String, Style)>, pub code: Option<DiagnosticId>, pub span: MultiSpan, @@ -117,11 +120,20 @@ impl Diagnostic { } } + #[inline(always)] + pub fn level(&self) -> Level { + self.level + } + pub fn is_error(&self) -> bool { match self.level { - Level::Bug | Level::Fatal | Level::Error { .. } | Level::FailureNote => true, + Level::Bug + | Level::DelayedBug + | Level::Fatal + | Level::Error { .. } + | Level::FailureNote => true, - Level::Warning | Level::Note | Level::Help | Level::Cancelled | Level::Allow => false, + Level::Warning | Level::Note | Level::Help | Level::Allow => false, } } @@ -139,15 +151,26 @@ impl Diagnostic { } } - /// Cancel the diagnostic (a structured diagnostic must either be emitted or - /// canceled or it will panic when dropped). - pub fn cancel(&mut self) { - self.level = Level::Cancelled; - } + /// Delay emission of this diagnostic as a bug. + /// + /// This can be useful in contexts where an error indicates a bug but + /// typically this only happens when other compilation errors have already + /// happened. In those cases this can be used to defer emission of this + /// diagnostic as a bug in the compiler only if no other errors have been + /// emitted. + /// + /// In the meantime, though, callsites are required to deal with the "bug" + /// locally in whichever way makes the most sense. + #[track_caller] + pub fn downgrade_to_delayed_bug(&mut self) -> &mut Self { + assert!( + self.is_error(), + "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error", + self.level + ); + self.level = Level::DelayedBug; - /// Check if this diagnostic [was cancelled][Self::cancel()]. - pub fn cancelled(&self) -> bool { - self.level == Level::Cancelled + self } /// Adds a span/label to be included in the resulting snippet. @@ -163,6 +186,20 @@ impl Diagnostic { self } + /// Labels all the given spans with the provided label. + /// See [`Self::span_label()`] for more information. + pub fn span_labels( + &mut self, + spans: impl IntoIterator<Item = Span>, + label: impl AsRef<str>, + ) -> &mut Self { + let label = label.as_ref(); + for span in spans { + self.span_label(span, label); + } + self + } + pub fn replace_span_with(&mut self, after: Span) -> &mut Self { let before = self.span.clone(); self.set_span(after); @@ -174,7 +211,7 @@ impl Diagnostic { self } - crate fn note_expected_found( + pub fn note_expected_found( &mut self, expected_label: &dyn fmt::Display, expected: DiagnosticStyledString, @@ -184,7 +221,7 @@ impl Diagnostic { self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"") } - crate fn note_unsuccessful_coercion( + pub fn note_unsuccessful_coercion( &mut self, expected: DiagnosticStyledString, found: DiagnosticStyledString, @@ -274,33 +311,33 @@ impl Diagnostic { /// Prints the span with a note above it. /// This is like [`Diagnostic::note()`], but it gets its own span. - crate fn span_note<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self { + pub fn span_note<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self { self.sub(Level::Note, msg, sp.into(), None); self } /// Add a warning attached to this diagnostic. - crate fn warn(&mut self, msg: &str) -> &mut Self { + pub fn warn(&mut self, msg: &str) -> &mut Self { self.sub(Level::Warning, msg, MultiSpan::new(), None); self } /// Prints the span with a warning above it. /// This is like [`Diagnostic::warn()`], but it gets its own span. - crate fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self { + pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self { self.sub(Level::Warning, msg, sp.into(), None); self } /// Add a help message attached to this diagnostic. - crate fn help(&mut self, msg: &str) -> &mut Self { + pub fn help(&mut self, msg: &str) -> &mut Self { self.sub(Level::Help, msg, MultiSpan::new(), None); self } /// Prints the span with some help above it. /// This is like [`Diagnostic::help()`], but it gets its own span. - crate fn span_help<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self { + pub fn span_help<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self { self.sub(Level::Help, msg, sp.into(), None); self } @@ -634,7 +671,7 @@ impl Diagnostic { self.code.clone() } - crate fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self { + pub fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self { self.message[0] = (msg.into(), Style::NoStyle); self } diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 3c8751a7a35..49305d22684 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -1,9 +1,10 @@ -use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString}; +use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString, ErrorReported}; use crate::{Handler, Level, StashKey}; use rustc_lint_defs::Applicability; use rustc_span::{MultiSpan, Span}; use std::fmt::{self, Debug}; +use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::thread::panicking; use tracing::debug; @@ -15,8 +16,25 @@ use tracing::debug; /// extending `HandlerFlags`, accessed via `self.handler.flags`. #[must_use] #[derive(Clone)] -pub struct DiagnosticBuilder<'a> { - handler: &'a Handler, +pub struct DiagnosticBuilder<'a, G: EmissionGuarantee> { + inner: DiagnosticBuilderInner<'a>, + _marker: PhantomData<G>, +} + +/// This type exists only for `DiagnosticBuilder::forget_guarantee`, because it: +/// 1. lacks the `G` parameter and therefore `DiagnosticBuilder<G1>` can be +/// converted into `DiagnosticBuilder<G2>` while reusing the `inner` field +/// 2. can implement the `Drop` "bomb" instead of `DiagnosticBuilder`, as it +/// contains all of the data (`state` + `diagnostic`) of `DiagnosticBuilder` +/// +/// The `diagnostic` field is not `Copy` and can't be moved out of whichever +/// type implements the `Drop` "bomb", but because of the above two facts, that +/// never needs to happen - instead, the whole `inner: DiagnosticBuilderInner` +/// can be moved out of a `DiagnosticBuilder` and into another. +#[must_use] +#[derive(Clone)] +struct DiagnosticBuilderInner<'a> { + state: DiagnosticBuilderState<'a>, /// `Diagnostic` is a large type, and `DiagnosticBuilder` is often used as a /// return value, especially within the frequently-used `PResult` type. @@ -25,6 +43,161 @@ pub struct DiagnosticBuilder<'a> { diagnostic: Box<Diagnostic>, } +#[derive(Clone)] +enum DiagnosticBuilderState<'a> { + /// Initial state of a `DiagnosticBuilder`, before `.emit()` or `.cancel()`. + /// + /// The `Diagnostic` will be emitted through this `Handler`. + Emittable(&'a Handler), + + /// State of a `DiagnosticBuilder`, after `.emit()` or *during* `.cancel()`. + /// + /// The `Diagnostic` will be ignored when calling `.emit()`, and it can be + /// assumed that `.emit()` was previously called, to end up in this state. + /// + /// While this is also used by `.cancel()`, this state is only observed by + /// the `Drop` `impl` of `DiagnosticBuilderInner`, as `.cancel()` takes + /// `self` by-value specifically to prevent any attempts to `.emit()`. + /// + // FIXME(eddyb) currently this doesn't prevent extending the `Diagnostic`, + // despite that being potentially lossy, if important information is added + // *after* the original `.emit()` call. + AlreadyEmittedOrDuringCancellation, +} + +// `DiagnosticBuilderState` should be pointer-sized. +rustc_data_structures::static_assert_size!( + DiagnosticBuilderState<'_>, + std::mem::size_of::<&Handler>() +); + +/// Trait for types that `DiagnosticBuilder::emit` can return as a "guarantee" +/// (or "proof") token that the emission happened. +pub trait EmissionGuarantee: Sized { + /// Implementation of `DiagnosticBuilder::emit`, fully controlled by each + /// `impl` of `EmissionGuarantee`, to make it impossible to create a value + /// of `Self` without actually performing the emission. + #[track_caller] + fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self; +} + +/// Private module for sealing the `IsError` helper trait. +mod sealed_level_is_error { + use crate::Level; + + /// Sealed helper trait for statically checking that a `Level` is an error. + crate trait IsError<const L: Level> {} + + impl IsError<{ Level::Bug }> for () {} + impl IsError<{ Level::DelayedBug }> for () {} + impl IsError<{ Level::Fatal }> for () {} + // NOTE(eddyb) `Level::Error { lint: true }` is also an error, but lints + // don't need error guarantees, as their levels are always dynamic. + impl IsError<{ Level::Error { lint: false } }> for () {} +} + +impl<'a> DiagnosticBuilder<'a, ErrorReported> { + /// Convenience function for internal use, clients should use one of the + /// `struct_*` methods on [`Handler`]. + crate fn new_guaranteeing_error<const L: Level>(handler: &'a Handler, message: &str) -> Self + where + (): sealed_level_is_error::IsError<L>, + { + Self { + inner: DiagnosticBuilderInner { + state: DiagnosticBuilderState::Emittable(handler), + diagnostic: Box::new(Diagnostic::new_with_code(L, None, message)), + }, + _marker: PhantomData, + } + } + + /// Discard the guarantee `.emit()` would return, in favor of having the + /// type `DiagnosticBuilder<'a, ()>`. This may be necessary whenever there + /// is a common codepath handling both errors and warnings. + pub fn forget_guarantee(self) -> DiagnosticBuilder<'a, ()> { + DiagnosticBuilder { inner: self.inner, _marker: PhantomData } + } +} + +// FIXME(eddyb) make `ErrorReported` impossible to create outside `.emit()`. +impl EmissionGuarantee for ErrorReported { + fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { + match db.inner.state { + // First `.emit()` call, the `&Handler` is still available. + DiagnosticBuilderState::Emittable(handler) => { + db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + + handler.emit_diagnostic(&db.inner.diagnostic); + + // Only allow a guarantee if the `level` wasn't switched to a + // non-error - the field isn't `pub`, but the whole `Diagnostic` + // can be overwritten with a new one, thanks to `DerefMut`. + assert!( + db.inner.diagnostic.is_error(), + "emitted non-error ({:?}) diagnostic \ + from `DiagnosticBuilder<ErrorReported>`", + db.inner.diagnostic.level, + ); + ErrorReported + } + // `.emit()` was previously called, disallowed from repeating it, + // but can take advantage of the previous `.emit()`'s guarantee + // still being applicable (i.e. as a form of idempotency). + DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => { + // Only allow a guarantee if the `level` wasn't switched to a + // non-error - the field isn't `pub`, but the whole `Diagnostic` + // can be overwritten with a new one, thanks to `DerefMut`. + assert!( + db.inner.diagnostic.is_error(), + "`DiagnosticBuilder<ErrorReported>`'s diagnostic \ + became non-error ({:?}), after original `.emit()`", + db.inner.diagnostic.level, + ); + ErrorReported + } + } + } +} + +impl<'a> DiagnosticBuilder<'a, ()> { + /// Convenience function for internal use, clients should use one of the + /// `struct_*` methods on [`Handler`]. + crate fn new(handler: &'a Handler, level: Level, message: &str) -> Self { + let diagnostic = Diagnostic::new_with_code(level, None, message); + Self::new_diagnostic(handler, diagnostic) + } + + /// Creates a new `DiagnosticBuilder` with an already constructed + /// diagnostic. + crate fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self { + debug!("Created new diagnostic"); + Self { + inner: DiagnosticBuilderInner { + state: DiagnosticBuilderState::Emittable(handler), + diagnostic: Box::new(diagnostic), + }, + _marker: PhantomData, + } + } +} + +// FIXME(eddyb) should there be a `Option<ErrorReported>` impl as well? +impl EmissionGuarantee for () { + fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { + match db.inner.state { + // First `.emit()` call, the `&Handler` is still available. + DiagnosticBuilderState::Emittable(handler) => { + db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + + handler.emit_diagnostic(&db.inner.diagnostic); + } + // `.emit()` was previously called, disallowed from repeating it. + DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} + } + } +} + /// In general, the `DiagnosticBuilder` uses deref to allow access to /// the fields and methods of the embedded `diagnostic` in a /// transparent way. *However,* many of the methods are intended to @@ -55,60 +228,54 @@ macro_rules! forward { $(#[$attrs])* #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")] pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { - self.diagnostic.$n($($name),*); - self - } - }; - - // Forward pattern for &mut self -> &mut Self, with generic parameters. - ( - $(#[$attrs:meta])* - pub fn $n:ident<$($generic:ident: $bound:path),*>( - &mut self, - $($name:ident: $ty:ty),* - $(,)? - ) -> &mut Self - ) => { - $(#[$attrs])* - #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")] - pub fn $n<$($generic: $bound),*>(&mut self, $($name: $ty),*) -> &mut Self { - self.diagnostic.$n($($name),*); + self.inner.diagnostic.$n($($name),*); self } }; } -impl<'a> Deref for DiagnosticBuilder<'a> { +impl<G: EmissionGuarantee> Deref for DiagnosticBuilder<'_, G> { type Target = Diagnostic; fn deref(&self) -> &Diagnostic { - &self.diagnostic + &self.inner.diagnostic } } -impl<'a> DerefMut for DiagnosticBuilder<'a> { +impl<G: EmissionGuarantee> DerefMut for DiagnosticBuilder<'_, G> { fn deref_mut(&mut self) -> &mut Diagnostic { - &mut self.diagnostic + &mut self.inner.diagnostic } } -impl<'a> DiagnosticBuilder<'a> { +impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// Emit the diagnostic. - pub fn emit(&mut self) { - self.handler.emit_diagnostic(&self); - self.cancel(); + #[track_caller] + pub fn emit(&mut self) -> G { + G::diagnostic_builder_emit_producing_guarantee(self) } /// Emit the diagnostic unless `delay` is true, /// in which case the emission will be delayed as a bug. /// /// See `emit` and `delay_as_bug` for details. - pub fn emit_unless(&mut self, delay: bool) { + #[track_caller] + pub fn emit_unless(&mut self, delay: bool) -> G { if delay { - self.delay_as_bug(); - } else { - self.emit(); + self.downgrade_to_delayed_bug(); } + self.emit() + } + + /// Cancel the diagnostic (a structured diagnostic must either be emitted or + /// cancelled or it will panic when dropped). + /// + /// This method takes `self` by-value to disallow calling `.emit()` on it, + /// which may be expected to *guarantee* the emission of an error, either + /// at the time of the call, or through a prior `.emit()` call. + pub fn cancel(mut self) { + self.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + drop(self); } /// Stashes diagnostic for possible later improvement in a different, @@ -123,21 +290,28 @@ impl<'a> DiagnosticBuilder<'a> { } /// Converts the builder to a `Diagnostic` for later emission, - /// unless handler has disabled such buffering. + /// unless handler has disabled such buffering, or `.emit()` was called. pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a Handler)> { - if self.handler.flags.dont_buffer_diagnostics - || self.handler.flags.treat_err_as_bug.is_some() - { + let handler = match self.inner.state { + // No `.emit()` calls, the `&Handler` is still available. + DiagnosticBuilderState::Emittable(handler) => handler, + // `.emit()` was previously called, nothing we can do. + DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => { + return None; + } + }; + + if handler.flags.dont_buffer_diagnostics || handler.flags.treat_err_as_bug.is_some() { self.emit(); return None; } - let handler = self.handler; + // Take the `Diagnostic` by replacing it with a dummy. + let dummy = Diagnostic::new(Level::Allow, ""); + let diagnostic = std::mem::replace(&mut *self.inner.diagnostic, dummy); - // We must use `Level::Cancelled` for `dummy` to avoid an ICE about an - // unused diagnostic. - let dummy = Diagnostic::new(Level::Cancelled, ""); - let diagnostic = std::mem::replace(&mut *self.diagnostic, dummy); + // Disable the ICE on `Drop`. + self.cancel(); // Logging here is useful to help track down where in logs an error was // actually emitted. @@ -162,12 +336,18 @@ impl<'a> DiagnosticBuilder<'a> { /// /// In the meantime, though, callsites are required to deal with the "bug" /// locally in whichever way makes the most sense. + #[track_caller] pub fn delay_as_bug(&mut self) { - self.level = Level::Bug; - self.handler.delay_as_bug((*self.diagnostic).clone()); - self.cancel(); + self.downgrade_to_delayed_bug(); + self.emit(); } + forward!( + #[track_caller] + pub fn downgrade_to_delayed_bug(&mut self,) -> &mut Self + ); + + forward!( /// Appends a labeled span to the diagnostic. /// /// Labels are used to convey additional context for the diagnostic's primary span. They will @@ -180,24 +360,16 @@ impl<'a> DiagnosticBuilder<'a> { /// the diagnostic was constructed. However, the label span is *not* considered a /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is /// primary. - pub fn span_label(&mut self, span: Span, label: impl Into<String>) -> &mut Self { - self.diagnostic.span_label(span, label); - self - } + pub fn span_label(&mut self, span: Span, label: impl Into<String>) -> &mut Self); + forward!( /// Labels all the given spans with the provided label. /// See [`Diagnostic::span_label()`] for more information. pub fn span_labels( &mut self, spans: impl IntoIterator<Item = Span>, label: impl AsRef<str>, - ) -> &mut Self { - let label = label.as_ref(); - for span in spans { - self.diagnostic.span_label(span, label); - } - self - } + ) -> &mut Self); forward!(pub fn note_expected_found( &mut self, @@ -224,17 +396,17 @@ impl<'a> DiagnosticBuilder<'a> { ) -> &mut Self); forward!(pub fn note(&mut self, msg: &str) -> &mut Self); - forward!(pub fn span_note<S: Into<MultiSpan>>( + forward!(pub fn span_note( &mut self, - sp: S, + sp: impl Into<MultiSpan>, msg: &str, ) -> &mut Self); forward!(pub fn warn(&mut self, msg: &str) -> &mut Self); - forward!(pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self); + forward!(pub fn span_warn(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> &mut Self); forward!(pub fn help(&mut self, msg: &str) -> &mut Self); - forward!(pub fn span_help<S: Into<MultiSpan>>( + forward!(pub fn span_help( &mut self, - sp: S, + sp: impl Into<MultiSpan>, msg: &str, ) -> &mut Self); forward!(pub fn set_is_lint(&mut self,) -> &mut Self); @@ -308,55 +480,35 @@ impl<'a> DiagnosticBuilder<'a> { applicability: Applicability, ) -> &mut Self); - forward!(pub fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self); - forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self); + forward!(pub fn set_primary_message(&mut self, msg: impl Into<String>) -> &mut Self); + forward!(pub fn set_span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self); forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); - - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`Handler`]. - crate fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> { - DiagnosticBuilder::new_with_code(handler, level, None, message) - } - - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`Handler`]. - crate fn new_with_code( - handler: &'a Handler, - level: Level, - code: Option<DiagnosticId>, - message: &str, - ) -> DiagnosticBuilder<'a> { - let diagnostic = Diagnostic::new_with_code(level, code, message); - DiagnosticBuilder::new_diagnostic(handler, diagnostic) - } - - /// Creates a new `DiagnosticBuilder` with an already constructed - /// diagnostic. - crate fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> { - debug!("Created new diagnostic"); - DiagnosticBuilder { handler, diagnostic: Box::new(diagnostic) } - } } -impl<'a> Debug for DiagnosticBuilder<'a> { +impl<G: EmissionGuarantee> Debug for DiagnosticBuilder<'_, G> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.diagnostic.fmt(f) + self.inner.diagnostic.fmt(f) } } -/// Destructor bomb - a `DiagnosticBuilder` must be either emitted or canceled +/// Destructor bomb - a `DiagnosticBuilder` must be either emitted or cancelled /// or we emit a bug. -impl<'a> Drop for DiagnosticBuilder<'a> { +impl Drop for DiagnosticBuilderInner<'_> { fn drop(&mut self) { - if !panicking() && !self.cancelled() { - let mut db = DiagnosticBuilder::new( - self.handler, - Level::Bug, - "the following error was constructed but not emitted", - ); - db.emit(); - self.emit(); - panic!(); + match self.state { + // No `.emit()` or `.cancel()` calls. + DiagnosticBuilderState::Emittable(handler) => { + if !panicking() { + handler.emit_diagnostic(&Diagnostic::new( + Level::Bug, + "the following error was constructed but not emitted", + )); + handler.emit_diagnostic(&self.diagnostic); + panic!(); + } + } + // `.emit()` was previously called, or maybe we're during `.cancel()`. + DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} } } } diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index ff3478073d9..dc28d1bb452 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -454,8 +454,14 @@ impl DiagnosticSpan { let end = je.sm.lookup_char_pos(span.hi()); let backtrace_step = backtrace.next().map(|bt| { let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je); - let def_site_span = - Self::from_span_full(bt.def_site, false, None, None, [].into_iter(), je); + let def_site_span = Self::from_span_full( + je.sm.guess_head_span(bt.def_site), + false, + None, + None, + [].into_iter(), + je, + ); Box::new(DiagnosticSpanMacroExpansion { span: call_site, macro_decl_name: bt.kind.descr(), diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index a5c954cca13..463308c27b2 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -9,6 +9,8 @@ #![feature(let_else)] #![feature(nll)] #![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] +#![feature(adt_const_params)] +#![allow(incomplete_features)] #[macro_use] extern crate rustc_macros; @@ -52,7 +54,7 @@ mod snippet; mod styled_buffer; pub use snippet::Style; -pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>; +pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a, ErrorReported>>; // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger. // (See also the comment on `DiagnosticBuilder`'s `diagnostic` field.) @@ -491,10 +493,15 @@ impl Drop for HandlerInner { self.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued"); } + // FIXME(eddyb) this explains what `delayed_good_path_bugs` are! + // They're `delayed_span_bugs` but for "require some diagnostic happened" + // instead of "require some error happened". Sadly that isn't ideal, as + // lints can be `#[allow]`'d, potentially leading to this triggering. + // Also, "good path" should be replaced with a better naming. if !self.has_any_message() { let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new()); self.flush_delayed( - bugs.into_iter().map(DelayedDiagnostic::decorate).collect(), + bugs.into_iter().map(DelayedDiagnostic::decorate), "no warnings or errors encountered even though `delayed_good_path_bugs` issued", ); } @@ -604,7 +611,7 @@ impl Handler { } /// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key. - pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_>> { + pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> { self.inner .borrow_mut() .stashed_diagnostics @@ -617,33 +624,17 @@ impl Handler { self.inner.borrow_mut().emit_stashed_diagnostics(); } - /// Construct a dummy builder with `Level::Cancelled`. - /// - /// Using this will neither report anything to the user (e.g. a warning), - /// nor will compilation cancel as a result. - pub fn struct_dummy(&self) -> DiagnosticBuilder<'_> { - DiagnosticBuilder::new(self, Level::Cancelled, "") - } - - /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. - /// - /// The builder will be canceled if warnings cannot be emitted. - pub fn struct_span_warn(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> { - let mut result = self.struct_warn(msg); - result.set_span(span); - result - } - /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. /// - /// This will "force" the warning meaning it will not be canceled even - /// if warnings cannot be emitted. - pub fn struct_span_force_warn( + /// Attempting to `.emit()` the builder will only emit if either: + /// * `can_emit_warnings` is `true` + /// * `is_force_warn` was set in `DiagnosticId::Lint` + pub fn struct_span_warn( &self, span: impl Into<MultiSpan>, msg: &str, - ) -> DiagnosticBuilder<'_> { - let mut result = self.struct_force_warn(msg); + ) -> DiagnosticBuilder<'_, ()> { + let mut result = self.struct_warn(msg); result.set_span(span); result } @@ -653,7 +644,7 @@ impl Handler { &self, span: impl Into<MultiSpan>, msg: &str, - ) -> DiagnosticBuilder<'_> { + ) -> DiagnosticBuilder<'_, ()> { let mut result = self.struct_allow(msg); result.set_span(span); result @@ -666,7 +657,7 @@ impl Handler { span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId, - ) -> DiagnosticBuilder<'_> { + ) -> DiagnosticBuilder<'_, ()> { let mut result = self.struct_span_warn(span, msg); result.code(code); result @@ -674,30 +665,24 @@ impl Handler { /// Construct a builder at the `Warning` level with the `msg`. /// - /// The builder will be canceled if warnings cannot be emitted. - pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_> { - let mut result = DiagnosticBuilder::new(self, Level::Warning, msg); - if !self.flags.can_emit_warnings { - result.cancel(); - } - result - } - - /// Construct a builder at the `Warning` level with the `msg`. - /// - /// This will "force" a warning meaning it will not be canceled even - /// if warnings cannot be emitted. - pub fn struct_force_warn(&self, msg: &str) -> DiagnosticBuilder<'_> { + /// Attempting to `.emit()` the builder will only emit if either: + /// * `can_emit_warnings` is `true` + /// * `is_force_warn` was set in `DiagnosticId::Lint` + pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_, ()> { DiagnosticBuilder::new(self, Level::Warning, msg) } /// Construct a builder at the `Allow` level with the `msg`. - pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_> { + pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_, ()> { DiagnosticBuilder::new(self, Level::Allow, msg) } /// Construct a builder at the `Error` level at the given `span` and with the `msg`. - pub fn struct_span_err(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> { + pub fn struct_span_err( + &self, + span: impl Into<MultiSpan>, + msg: &str, + ) -> DiagnosticBuilder<'_, ErrorReported> { let mut result = self.struct_err(msg); result.set_span(span); result @@ -709,7 +694,7 @@ impl Handler { span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId, - ) -> DiagnosticBuilder<'_> { + ) -> DiagnosticBuilder<'_, ErrorReported> { let mut result = self.struct_span_err(span, msg); result.code(code); result @@ -717,18 +702,22 @@ impl Handler { /// Construct a builder at the `Error` level with the `msg`. // FIXME: This method should be removed (every error should have an associated error code). - pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> { - DiagnosticBuilder::new(self, Level::Error { lint: false }, msg) + pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorReported> { + DiagnosticBuilder::new_guaranteeing_error::<{ Level::Error { lint: false } }>(self, msg) } /// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors. #[doc(hidden)] - pub fn struct_err_lint(&self, msg: &str) -> DiagnosticBuilder<'_> { + pub fn struct_err_lint(&self, msg: &str) -> DiagnosticBuilder<'_, ()> { DiagnosticBuilder::new(self, Level::Error { lint: true }, msg) } /// Construct a builder at the `Error` level with the `msg` and the `code`. - pub fn struct_err_with_code(&self, msg: &str, code: DiagnosticId) -> DiagnosticBuilder<'_> { + pub fn struct_err_with_code( + &self, + msg: &str, + code: DiagnosticId, + ) -> DiagnosticBuilder<'_, ErrorReported> { let mut result = self.struct_err(msg); result.code(code); result @@ -739,7 +728,7 @@ impl Handler { &self, span: impl Into<MultiSpan>, msg: &str, - ) -> DiagnosticBuilder<'_> { + ) -> DiagnosticBuilder<'_, ErrorReported> { let mut result = self.struct_fatal(msg); result.set_span(span); result @@ -751,24 +740,24 @@ impl Handler { span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId, - ) -> DiagnosticBuilder<'_> { + ) -> DiagnosticBuilder<'_, ErrorReported> { let mut result = self.struct_span_fatal(span, msg); result.code(code); result } /// Construct a builder at the `Error` level with the `msg`. - pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_> { - DiagnosticBuilder::new(self, Level::Fatal, msg) + pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorReported> { + DiagnosticBuilder::new_guaranteeing_error::<{ Level::Fatal }>(self, msg) } /// Construct a builder at the `Help` level with the `msg`. - pub fn struct_help(&self, msg: &str) -> DiagnosticBuilder<'_> { + pub fn struct_help(&self, msg: &str) -> DiagnosticBuilder<'_, ()> { DiagnosticBuilder::new(self, Level::Help, msg) } /// Construct a builder at the `Note` level with the `msg`. - pub fn struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_> { + pub fn struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_, ()> { DiagnosticBuilder::new(self, Level::Note, msg) } @@ -815,6 +804,8 @@ impl Handler { self.inner.borrow_mut().delay_span_bug(span, msg) } + // FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's + // where the explanation of what "good path" is (also, it should be renamed). pub fn delay_good_path_bug(&self, msg: &str) { self.inner.borrow_mut().delay_good_path_bug(msg) } @@ -827,7 +818,7 @@ impl Handler { self.emit_diag_at_span(Diagnostic::new(Note, msg), span); } - pub fn span_note_diag(&self, span: Span, msg: &str) -> DiagnosticBuilder<'_> { + pub fn span_note_diag(&self, span: Span, msg: &str) -> DiagnosticBuilder<'_, ()> { let mut db = DiagnosticBuilder::new(self, Note, msg); db.set_span(span); db @@ -915,10 +906,6 @@ impl Handler { pub fn emit_unused_externs(&self, lint_level: &str, unused_externs: &[&str]) { self.inner.borrow_mut().emit_unused_externs(lint_level, unused_externs) } - - pub fn delay_as_bug(&self, diagnostic: Diagnostic) { - self.inner.borrow_mut().delay_as_bug(diagnostic) - } } impl HandlerInner { @@ -936,9 +923,18 @@ impl HandlerInner { diags.iter().for_each(|diag| self.emit_diagnostic(diag)); } + // FIXME(eddyb) this should ideally take `diagnostic` by value. fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) { - if diagnostic.cancelled() { - return; + if diagnostic.level == Level::DelayedBug { + // FIXME(eddyb) this should check for `has_errors` and stop pushing + // once *any* errors were emitted (and truncate `delayed_span_bugs` + // when an error is first emitted, also), but maybe there's a case + // in which that's not sound? otherwise this is really inefficient. + self.delayed_span_bugs.push(diagnostic.clone()); + + if !self.flags.report_delayed_bugs { + return; + } } if diagnostic.has_future_breakage() { @@ -1119,14 +1115,16 @@ impl HandlerInner { // FIXME: don't abort here if report_delayed_bugs is off self.span_bug(sp, msg); } - let mut diagnostic = Diagnostic::new(Level::Bug, msg); + let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg); diagnostic.set_span(sp.into()); diagnostic.note(&format!("delayed at {}", std::panic::Location::caller())); - self.delay_as_bug(diagnostic) + self.emit_diagnostic(&diagnostic) } + // FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's + // where the explanation of what "good path" is (also, it should be renamed). fn delay_good_path_bug(&mut self, msg: &str) { - let diagnostic = Diagnostic::new(Level::Bug, msg); + let diagnostic = Diagnostic::new(Level::DelayedBug, msg); if self.flags.report_delayed_bugs { self.emit_diagnostic(&diagnostic); } @@ -1160,20 +1158,34 @@ impl HandlerInner { panic::panic_any(ExplicitBug); } - fn delay_as_bug(&mut self, diagnostic: Diagnostic) { - if self.flags.report_delayed_bugs { - self.emit_diagnostic(&diagnostic); - } - self.delayed_span_bugs.push(diagnostic); - } + fn flush_delayed(&mut self, bugs: impl IntoIterator<Item = Diagnostic>, explanation: &str) { + let mut no_bugs = true; + for mut bug in bugs { + if no_bugs { + // Put the overall explanation before the `DelayedBug`s, to + // frame them better (e.g. separate warnings from them). + self.emit_diagnostic(&Diagnostic::new(Bug, explanation)); + no_bugs = false; + } + + // "Undelay" the `DelayedBug`s (into plain `Bug`s). + if bug.level != Level::DelayedBug { + // NOTE(eddyb) not panicking here because we're already producing + // an ICE, and the more information the merrier. + bug.note(&format!( + "`flushed_delayed` got diagnostic with level {:?}, \ + instead of the expected `DelayedBug`", + bug.level, + )); + } + bug.level = Level::Bug; - fn flush_delayed(&mut self, bugs: Vec<Diagnostic>, explanation: &str) { - let has_bugs = !bugs.is_empty(); - for bug in bugs { self.emit_diagnostic(&bug); } - if has_bugs { - panic!("{}", explanation); + + // Panic with `ExplicitBug` to avoid "unexpected panic" messages. + if !no_bugs { + panic::panic_any(ExplicitBug); } } @@ -1224,9 +1236,10 @@ impl DelayedDiagnostic { } } -#[derive(Copy, PartialEq, Clone, Hash, Debug, Encodable, Decodable)] +#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)] pub enum Level { Bug, + DelayedBug, Fatal, Error { /// If this error comes from a lint, don't abort compilation even when abort_if_errors() is called. @@ -1235,7 +1248,6 @@ pub enum Level { Warning, Note, Help, - Cancelled, FailureNote, Allow, } @@ -1250,7 +1262,7 @@ impl Level { fn color(self) -> ColorSpec { let mut spec = ColorSpec::new(); match self { - Bug | Fatal | Error { .. } => { + Bug | DelayedBug | Fatal | Error { .. } => { spec.set_fg(Some(Color::Red)).set_intense(true); } Warning => { @@ -1263,20 +1275,19 @@ impl Level { spec.set_fg(Some(Color::Cyan)).set_intense(true); } FailureNote => {} - Allow | Cancelled => unreachable!(), + Allow => unreachable!(), } spec } pub fn to_str(self) -> &'static str { match self { - Bug => "error: internal compiler error", + Bug | DelayedBug => "error: internal compiler error", Fatal | Error { .. } => "error", Warning => "warning", Note => "note", Help => "help", FailureNote => "failure-note", - Cancelled => panic!("Shouldn't call on cancelled error"), Allow => panic!("Shouldn't call on allowed error"), } } @@ -1286,9 +1297,10 @@ impl Level { } } +// FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite. pub fn add_elided_lifetime_in_path_suggestion( source_map: &SourceMap, - db: &mut DiagnosticBuilder<'_>, + diag: &mut Diagnostic, n: usize, path_span: Span, incl_angl_brckt: bool, @@ -1320,7 +1332,7 @@ pub fn add_elided_lifetime_in_path_suggestion( (insertion_span, anon_lts) } }; - db.span_suggestion( + diag.span_suggestion( replace_span, &format!("indicate the anonymous lifetime{}", pluralize!(n)), suggestion, diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 2bdf3b39126..4e951ad9d4b 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -10,7 +10,7 @@ use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind}; use rustc_attr::{self as attr, Deprecation, Stability}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{self, Lrc}; -use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported, PResult}; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; use rustc_lint_defs::BuiltinLintDiagnostics; use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS}; @@ -1072,7 +1072,11 @@ impl<'a> ExtCtxt<'a> { self.current_expansion.id.expansion_cause() } - pub fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'a> { + pub fn struct_span_err<S: Into<MultiSpan>>( + &self, + sp: S, + msg: &str, + ) -> DiagnosticBuilder<'a, ErrorReported> { self.sess.parse_sess.span_diagnostic.struct_span_err(sp, msg) } @@ -1130,11 +1134,7 @@ impl<'a> ExtCtxt<'a> { /// This unifies the logic used for resolving `include_X!`. /// /// FIXME: move this to `rustc_builtin_macros` and make it private. - pub fn resolve_path( - &self, - path: impl Into<PathBuf>, - span: Span, - ) -> Result<PathBuf, DiagnosticBuilder<'a>> { + pub fn resolve_path(&self, path: impl Into<PathBuf>, span: Span) -> PResult<'a, PathBuf> { let path = path.into(); // Relative paths are resolved relative to the file in which they are found @@ -1174,7 +1174,7 @@ pub fn expr_to_spanned_string<'a>( cx: &'a mut ExtCtxt<'_>, expr: P<ast::Expr>, err_msg: &str, -) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a>, bool)>> { +) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a, ErrorReported>, bool)>> { // Perform eager expansion on the expression. // We want to be able to handle e.g., `concat!("foo", "bar")`. let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); @@ -1233,7 +1233,9 @@ pub fn check_zero_tts(cx: &ExtCtxt<'_>, sp: Span, tts: TokenStream, name: &str) pub fn parse_expr(p: &mut parser::Parser<'_>) -> Option<P<ast::Expr>> { match p.parse_expr() { Ok(e) => return Some(e), - Err(mut err) => err.emit(), + Err(mut err) => { + err.emit(); + } } while p.token != token::Eof { p.bump(); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index f71fb58cf6b..4af7d2b7ec6 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -16,7 +16,7 @@ use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, TransparencyError}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; use rustc_feature::Features; use rustc_lint_defs::builtin::{ RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, @@ -49,11 +49,7 @@ crate struct ParserAnyMacro<'a> { is_local: bool, } -crate fn annotate_err_with_kind( - err: &mut DiagnosticBuilder<'_>, - kind: AstFragmentKind, - span: Span, -) { +crate fn annotate_err_with_kind(err: &mut Diagnostic, kind: AstFragmentKind, span: Span) { match kind { AstFragmentKind::Ty => { err.span_label(span, "this macro call doesn't expand to a type"); @@ -66,7 +62,7 @@ crate fn annotate_err_with_kind( } fn emit_frag_parse_err( - mut e: DiagnosticBuilder<'_>, + mut e: DiagnosticBuilder<'_, rustc_errors::ErrorReported>, parser: &Parser<'_>, orig_parser: &mut Parser<'_>, site_span: Span, @@ -99,7 +95,7 @@ fn emit_frag_parse_err( match kind { // Try a statement if an expression is wanted but failed and suggest adding `;` to call. AstFragmentKind::Expr => match parse_ast_fragment(orig_parser, AstFragmentKind::Stmts) { - Err(mut err) => err.cancel(), + Err(err) => err.cancel(), Ok(_) => { e.note( "the macro call doesn't expand to an expression, but it can expand to a statement", diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index aa54bdbd3a7..1ce3766579b 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -1,7 +1,7 @@ use crate::base::ModuleData; use rustc_ast::ptr::P; use rustc_ast::{token, Attribute, Inline, Item}; -use rustc_errors::{struct_span_err, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorReported}; use rustc_parse::new_parser_from_file; use rustc_parse::validate_attr; use rustc_session::parse::ParseSess; @@ -39,7 +39,7 @@ pub enum ModError<'a> { ModInBlock(Option<Ident>), FileNotFound(Ident, PathBuf, PathBuf), MultipleCandidates(Ident, PathBuf, PathBuf), - ParserError(DiagnosticBuilder<'a>), + ParserError(DiagnosticBuilder<'a, ErrorReported>), } crate fn parse_external_mod( @@ -242,7 +242,7 @@ pub fn default_submod_path<'a>( } impl ModError<'_> { - fn report(self, sess: &Session, span: Span) { + fn report(self, sess: &Session, span: Span) -> ErrorReported { let diag = &sess.parse_sess.span_diagnostic; match self { ModError::CircularInclusion(file_paths) => { diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 99a945b1c91..869cada400f 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -446,7 +446,9 @@ impl server::TokenStream for Rustc<'_, '_> { } expr }; - let expr = expr.map_err(|mut err| err.emit())?; + let expr = expr.map_err(|mut err| { + err.emit(); + })?; // Perform eager expansion on the expression. let expr = self diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d48c8e81f54..72c02932945 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -15,6 +15,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_index::vec::IndexVec; use rustc_macros::HashStable_Generic; +use rustc_span::hygiene::MacroKind; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{def_id::LocalDefId, BytePos, MultiSpan, Span, DUMMY_SP}; @@ -2803,7 +2804,7 @@ pub enum ItemKind<'hir> { /// A function declaration. Fn(FnSig<'hir>, Generics<'hir>, BodyId), /// A MBE macro definition (`macro_rules!` or `macro`). - Macro(ast::MacroDef), + Macro(ast::MacroDef, MacroKind), /// A module. Mod(Mod<'hir>), /// An external module, e.g. `extern { .. }`. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index c55f2a7b039..1b40f3d390e 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -575,7 +575,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { item.span, item.hir_id(), ), - ItemKind::Macro(_) => { + ItemKind::Macro(..) => { visitor.visit_id(item.hir_id()); } ItemKind::Mod(ref module) => { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 8e45b636f47..b3042c61002 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -570,7 +570,7 @@ impl<'a> State<'a> { self.end(); // need to close a box self.ann.nested(self, Nested::Body(body)); } - hir::ItemKind::Macro(ref macro_def) => { + hir::ItemKind::Macro(ref macro_def, _) => { self.print_mac_def(macro_def, &item.ident, item.span, |state| { state.print_visibility(&item.vis) }); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 91215cbb17c..317481a037d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -58,7 +58,7 @@ use crate::traits::{ }; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{pluralize, struct_span_err}; +use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorReported}; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -85,7 +85,7 @@ pub mod nice_region_error; pub(super) fn note_and_explain_region<'tcx>( tcx: TyCtxt<'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, prefix: &str, region: ty::Region<'tcx>, suffix: &str, @@ -118,7 +118,7 @@ pub(super) fn note_and_explain_region<'tcx>( fn explain_free_region<'tcx>( tcx: TyCtxt<'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, prefix: &str, region: ty::Region<'tcx>, suffix: &str, @@ -194,7 +194,7 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>( } fn emit_msg_span( - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, prefix: &str, description: String, span: Option<Span>, @@ -210,7 +210,7 @@ fn emit_msg_span( } fn label_msg_span( - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, prefix: &str, description: String, span: Option<Span>, @@ -230,7 +230,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( span: Span, hidden_ty: Ty<'tcx>, hidden_region: ty::Region<'tcx>, -) -> DiagnosticBuilder<'tcx> { +) -> DiagnosticBuilder<'tcx, ErrorReported> { let mut err = struct_span_err!( tcx.sess, span, @@ -471,11 +471,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Adds a note if the types come from similarly named crates - fn check_and_note_conflicting_crates( - &self, - err: &mut DiagnosticBuilder<'_>, - terr: &TypeError<'tcx>, - ) { + fn check_and_note_conflicting_crates(&self, err: &mut Diagnostic, terr: &TypeError<'tcx>) { use hir::def_id::CrateNum; use rustc_hir::definitions::DisambiguatedDefPathData; use ty::print::Printer; @@ -557,7 +553,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - let report_path_match = |err: &mut DiagnosticBuilder<'_>, did1: DefId, did2: DefId| { + let report_path_match = |err: &mut Diagnostic, did1: DefId, did2: DefId| { // Only external crates, if either is from a local // module we could have false positives if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate { @@ -598,7 +594,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn note_error_origin( &self, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut Diagnostic, cause: &ObligationCause<'tcx>, exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>, terr: &TypeError<'tcx>, @@ -792,7 +788,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn suggest_boxing_for_return_impl_trait( &self, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut Diagnostic, return_sp: Span, arm_spans: impl Iterator<Item = Span>, ) { @@ -1436,7 +1432,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// E0271, like `src/test/ui/issues/issue-39970.stderr`. pub fn note_type_err( &self, - diag: &mut DiagnosticBuilder<'tcx>, + diag: &mut Diagnostic, cause: &ObligationCause<'tcx>, secondary_span: Option<(Span, String)>, mut values: Option<ValuePairs<'tcx>>, @@ -1483,14 +1479,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { types_visitor } - fn report(&self, err: &mut DiagnosticBuilder<'_>) { + fn report(&self, err: &mut Diagnostic) { self.add_labels_for_types(err, "expected", &self.expected); self.add_labels_for_types(err, "found", &self.found); } fn add_labels_for_types( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, target: &str, types: &FxHashMap<TyCategory, FxHashSet<Span>>, ) { @@ -1601,7 +1597,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Some((expected, found)) => Some((expected, found)), None => { // Derived error. Cancel the emitter. - diag.cancel(); + // NOTE(eddyb) this was `.cancel()`, but `diag` + // is borrowed, so we can't fully defuse it. + diag.downgrade_to_delayed_bug(); return; } }; @@ -1817,7 +1815,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, exp_span: Span, exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, - diag: &mut DiagnosticBuilder<'tcx>, + diag: &mut Diagnostic, ) { debug!( "suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}", @@ -1905,7 +1903,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, cause: &ObligationCause<'tcx>, exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, - diag: &mut DiagnosticBuilder<'tcx>, + diag: &mut Diagnostic, ) { debug!( "suggest_accessing_field_where_appropriate(cause={:?}, exp_found={:?})", @@ -1954,7 +1952,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, span: Span, exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, - diag: &mut DiagnosticBuilder<'tcx>, + diag: &mut Diagnostic, ) { if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) = (exp_found.expected.kind(), exp_found.found.kind()) @@ -2015,7 +2013,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { use crate::traits::ObligationCauseCode::MatchExpressionArm; debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); @@ -2107,7 +2105,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn emit_tuple_wrap_err( &self, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut Diagnostic, span: Span, found: Ty<'tcx>, expected_fields: &List<Ty<'tcx>>, @@ -2223,7 +2221,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: Option<SubregionOrigin<'tcx>>, bound_kind: GenericKind<'tcx>, sub: Region<'tcx>, - ) -> DiagnosticBuilder<'a> { + ) -> DiagnosticBuilder<'a, ErrorReported> { let hir = self.tcx.hir(); // Attempt to obtain the span of the parameter so we can // suggest adding an explicit lifetime bound to it. @@ -2339,7 +2337,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } fn binding_suggestion<'tcx, S: fmt::Display>( - err: &mut DiagnosticBuilder<'tcx>, + err: &mut Diagnostic, type_param_span: Option<(Span, bool, bool)>, bound_kind: GenericKind<'tcx>, sub: S, @@ -2373,7 +2371,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let new_binding_suggestion = - |err: &mut DiagnosticBuilder<'tcx>, + |err: &mut Diagnostic, type_param_span: Option<(Span, bool, bool)>, bound_kind: GenericKind<'tcx>| { let msg = "consider introducing an explicit lifetime bound"; @@ -2649,7 +2647,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn report_inference_failure( &self, var_origin: RegionVariableOrigin, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let br_string = |br: ty::BoundRegionKind| { let mut s = match br { ty::BrNamed(_, name) => name.to_string(), diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index ff734c99f3e..067f19bbe94 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1,6 +1,8 @@ use crate::infer::type_variable::TypeVariableOriginKind; use crate::infer::{InferCtxt, Symbol}; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{ + pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorReported, +}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::def_id::DefId; @@ -195,7 +197,7 @@ impl UseDiagnostic<'_> { } } - fn attach_note(&self, err: &mut DiagnosticBuilder<'_>) { + fn attach_note(&self, err: &mut Diagnostic) { match *self { Self::TryConversion { pre_ty, post_ty, .. } => { let intro = "`?` implicitly converts the error value"; @@ -224,7 +226,7 @@ impl UseDiagnostic<'_> { /// Suggest giving an appropriate return type to a closure expression. fn closure_return_type_suggestion( - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, output: &FnRetTy<'_>, body: &Body<'_>, ret: &str, @@ -488,7 +490,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { arg: GenericArg<'tcx>, impl_candidates: Vec<ty::TraitRef<'tcx>>, error_code: TypeAnnotationNeeded, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let arg = self.resolve_vars_if_possible(arg); let arg_data = self.extract_inference_diagnostics_data(arg, None); @@ -868,7 +870,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, segment: &hir::PathSegment<'_>, e: &Expr<'_>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, ) { if let (Some(typeck_results), None) = (self.in_progress_typeck_results, &segment.args) { let borrow = typeck_results.borrow(); @@ -913,7 +915,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { kind: hir::GeneratorKind, span: Span, ty: Ty<'tcx>, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let ty = self.resolve_vars_if_possible(ty); let data = self.extract_inference_diagnostics_data(ty.into(), None); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index 4eec492b3ae..bbbb0f79acc 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -7,7 +7,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::SubregionOrigin; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorReported}; use rustc_hir as hir; use rustc_hir::{GenericParamKind, Ty}; use rustc_middle::ty::Region; @@ -156,7 +156,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { sub: Region<'tcx>, ty_sup: &Ty<'_>, ty_sub: &Ty<'_>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, ) { if let ( hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. }, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index f44e6e04346..a8b878ae344 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -46,7 +46,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { self.infcx.tcx } - pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx>> { + pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx, ErrorReported>> { // Due to the improved diagnostics returned by the MIR borrow checker, only a subset of // the nice region errors are required when running under the MIR borrow checker. self.try_report_named_anon_conflict().or_else(|| self.try_report_placeholder_conflict()) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 17ff5d45c89..825aadaad9a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -2,13 +2,15 @@ //! where one region is named and the other is anonymous. use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_middle::ty; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// When given a `ConcreteFailure` for a function with parameters containing a named region and /// an anonymous region, emit an descriptive diagnostic error. - pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<'tcx>> { + pub(super) fn try_report_named_anon_conflict( + &self, + ) -> Option<DiagnosticBuilder<'tcx, ErrorReported>> { let (span, sub, sup) = self.regions()?; debug!( diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index bf9c2246dd8..5ce5d44e51d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -4,7 +4,7 @@ use crate::infer::ValuePairs; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::intern::Interned; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorReported}; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; use rustc_middle::ty::error::ExpectedFound; @@ -17,7 +17,9 @@ use std::fmt::{self, Write}; impl<'tcx> NiceRegionError<'_, 'tcx> { /// When given a `ConcreteFailure` for a function with arguments containing a named region and /// an anonymous region, emit a descriptive diagnostic error. - pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder<'tcx>> { + pub(super) fn try_report_placeholder_conflict( + &self, + ) -> Option<DiagnosticBuilder<'tcx, ErrorReported>> { match &self.error { /////////////////////////////////////////////////////////////////////////// // NB. The ordering of cases in this match is very @@ -153,7 +155,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { sub_placeholder: Option<Region<'tcx>>, sup_placeholder: Option<Region<'tcx>>, value_pairs: &ValuePairs<'tcx>, - ) -> Option<DiagnosticBuilder<'tcx>> { + ) -> Option<DiagnosticBuilder<'tcx, ErrorReported>> { let (expected_substs, found_substs, trait_def_id) = match value_pairs { ValuePairs::TraitRefs(ExpectedFound { expected, found }) if expected.def_id == found.def_id => @@ -201,7 +203,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { trait_def_id: DefId, expected_substs: SubstsRef<'tcx>, actual_substs: SubstsRef<'tcx>, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let span = cause.span(self.tcx()); let msg = format!( "implementation of `{}` is not general enough", @@ -306,7 +308,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { /// due to the number of combinations we have to deal with. fn explain_actual_impl_that_was_found( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, sub_placeholder: Option<Region<'tcx>>, sup_placeholder: Option<Region<'tcx>>, has_sub: Option<usize>, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 8601180842c..210743d7cef 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -5,7 +5,7 @@ use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_data_structures::stable_set::FxHashSet; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorReported}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; @@ -286,7 +286,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { pub fn suggest_new_region_bound( tcx: TyCtxt<'_>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, fn_returns: Vec<&rustc_hir::Ty<'_>>, lifetime_name: String, arg: Option<String>, @@ -483,7 +483,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// `'static` obligation. Suggest relaxing that implicit bound. fn find_impl_on_dyn_trait( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, ty: Ty<'_>, ctxt: &UnifyReceiverContext<'tcx>, ) -> bool { @@ -514,7 +514,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { fn suggest_constrain_dyn_trait_in_impl( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, found_dids: &FxHashSet<DefId>, ident: Ident, self_ty: &hir::Ty<'_>, diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 8671ecba6e9..5dc8c894608 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -1,16 +1,12 @@ use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt}; use crate::infer::{self, InferCtxt, SubregionOrigin}; -use rustc_errors::{struct_span_err, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, ErrorReported}; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Region}; impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub(super) fn note_region_origin( - &self, - err: &mut DiagnosticBuilder<'_>, - origin: &SubregionOrigin<'tcx>, - ) { + pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) { let mut label_or_note = |span, msg| { let sub_count = err.children.iter().filter(|d| d.span.is_dummy()).count(); let expanded_sub_count = err.children.iter().filter(|d| !d.span.is_dummy()).count(); @@ -113,7 +109,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { match origin { infer::Subtype(box trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); @@ -405,7 +401,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { placeholder_origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { // I can't think how to do better than this right now. -nikomatsakis debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure"); match placeholder_origin { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 57ac98ca897..95608f413d5 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -14,7 +14,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::Rollback; use rustc_data_structures::unify as ut; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::{DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; @@ -1475,19 +1475,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { sp: Span, mk_diag: M, actual_ty: Ty<'tcx>, - ) -> DiagnosticBuilder<'tcx> + ) -> DiagnosticBuilder<'tcx, ErrorReported> where - M: FnOnce(String) -> DiagnosticBuilder<'tcx>, + M: FnOnce(String) -> DiagnosticBuilder<'tcx, ErrorReported>, { let actual_ty = self.resolve_vars_if_possible(actual_ty); debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); + let mut err = mk_diag(self.ty_to_string(actual_ty)); + // Don't report an error if actual type is `Error`. if actual_ty.references_error() { - return self.tcx.sess.diagnostic().struct_dummy(); + err.downgrade_to_delayed_bug(); } - mk_diag(self.ty_to_string(actual_ty)) + err } pub fn report_mismatched_types( @@ -1496,7 +1498,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { expected: Ty<'tcx>, actual: Ty<'tcx>, err: TypeError<'tcx>, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let trace = TypeTrace::types(cause, true, expected, actual); self.report_and_explain_type_error(trace, &err) } @@ -1507,7 +1509,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { expected: ty::Const<'tcx>, actual: ty::Const<'tcx>, err: TypeError<'tcx>, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let trace = TypeTrace::consts(cause, true, expected, actual); self.report_and_explain_type_error(trace, &err) } diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 1a5ffd93701..35430849290 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -2,7 +2,7 @@ use super::ObjectSafetyViolation; use crate::infer::InferCtxt; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{struct_span_err, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::TyCtxt; @@ -17,7 +17,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { impl_item_def_id: DefId, trait_item_def_id: DefId, requirement: &dyn fmt::Display, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let msg = "impl has stricter requirements than trait"; let sp = self.tcx.sess.source_map().guess_head_span(error_span); @@ -40,7 +40,7 @@ pub fn report_object_safety_error<'tcx>( span: Span, trait_def_id: DefId, violations: &[ObjectSafetyViolation], -) -> DiagnosticBuilder<'tcx> { +) -> DiagnosticBuilder<'tcx, ErrorReported> { let trait_str = tcx.def_path_str(trait_def_id); let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node { hir::Node::Item(item) => Some(item.ident.span), diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 609fc4b78c0..20835262324 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -102,7 +102,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String } match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) { - Ok(mut parser) => match &mut parser.parse_meta_item() { + Ok(mut parser) => match parser.parse_meta_item() { Ok(meta_item) if parser.token == token::Eof => { if meta_item.path.segments.len() != 1 { error!("argument key must be an identifier"); @@ -121,7 +121,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String Ok(..) => {} Err(err) => err.cancel(), }, - Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()), + Err(errs) => drop(errs), } // If the user tried to use a key="value" flag, but is missing the quotes, provide @@ -165,15 +165,16 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg { } match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) { - Ok(mut parser) => match &mut parser.parse_meta_item() { + Ok(mut parser) => match parser.parse_meta_item() { Ok(meta_item) if parser.token == token::Eof => { if let Some(args) = meta_item.meta_item_list() { if meta_item.has_name(sym::names) { - cfg.names_checked = true; + let names_valid = + cfg.names_valid.get_or_insert_with(|| FxHashSet::default()); for arg in args { if arg.is_word() && arg.ident().is_some() { let ident = arg.ident().expect("multi-segment cfg key"); - cfg.names_valid.insert(ident.name.to_string()); + names_valid.insert(ident.name.to_string()); } else { error!("`names()` arguments must be simple identifers"); } @@ -183,13 +184,16 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg { if let Some((name, values)) = args.split_first() { if name.is_word() && name.ident().is_some() { let ident = name.ident().expect("multi-segment cfg key"); - cfg.values_checked.insert(ident.to_string()); + let ident_values = cfg + .values_valid + .entry(ident.name.to_string()) + .or_insert_with(|| FxHashSet::default()); + for val in values { if let Some(LitKind::Str(s, _)) = val.literal().map(|lit| &lit.kind) { - cfg.values_valid - .insert((ident.to_string(), s.to_string())); + ident_values.insert(s.to_string()); } else { error!( "`values()` arguments must be string literals" @@ -210,7 +214,7 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg { Ok(..) => {} Err(err) => err.cancel(), }, - Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()), + Err(errs) => drop(errs), } error!( @@ -219,7 +223,9 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg { ); } - cfg.names_valid.extend(cfg.values_checked.iter().cloned()); + if let Some(names_valid) = &mut cfg.names_valid { + names_valid.extend(cfg.values_valid.keys().cloned()); + } cfg }) } diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index d789237e692..97f9588ae1e 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -159,26 +159,8 @@ impl Mode { } } -fn scan_escape(first_char: char, chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> { - if first_char != '\\' { - // Previous character was not a slash, and we don't expect it to be - // an escape-only character. - return match first_char { - '\t' | '\n' => Err(EscapeError::EscapeOnlyChar), - '\r' => Err(EscapeError::BareCarriageReturn), - '\'' if mode.in_single_quotes() => Err(EscapeError::EscapeOnlyChar), - '"' if mode.in_double_quotes() => Err(EscapeError::EscapeOnlyChar), - _ => { - if mode.is_bytes() && !first_char.is_ascii() { - // Byte literal can't be a non-ascii character. - return Err(EscapeError::NonAsciiCharInByte); - } - Ok(first_char) - } - }; - } - - // Previous character is '\\', try to unescape it. +fn scan_escape(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> { + // Previous character was '\\', unescape what follows. let second_char = chars.next().ok_or(EscapeError::LoneSlash)?; @@ -270,9 +252,24 @@ fn scan_escape(first_char: char, chars: &mut Chars<'_>, mode: Mode) -> Result<ch Ok(res) } +#[inline] +fn ascii_check(first_char: char, mode: Mode) -> Result<char, EscapeError> { + if mode.is_bytes() && !first_char.is_ascii() { + // Byte literal can't be a non-ascii character. + Err(EscapeError::NonAsciiCharInByte) + } else { + Ok(first_char) + } +} + fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> { let first_char = chars.next().ok_or(EscapeError::ZeroChars)?; - let res = scan_escape(first_char, chars, mode)?; + let res = match first_char { + '\\' => scan_escape(chars, mode), + '\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar), + '\r' => Err(EscapeError::BareCarriageReturn), + _ => ascii_check(first_char, mode), + }?; if chars.next().is_some() { return Err(EscapeError::MoreThanOneChar); } @@ -303,12 +300,14 @@ where skip_ascii_whitespace(&mut chars, start, callback); continue; } - _ => scan_escape(first_char, &mut chars, mode), + _ => scan_escape(&mut chars, mode), } } '\n' => Ok('\n'), '\t' => Ok('\t'), - _ => scan_escape(first_char, &mut chars, mode), + '"' => Err(EscapeError::EscapeOnlyChar), + '\r' => Err(EscapeError::BareCarriageReturn), + _ => ascii_check(first_char, mode), }; let end = initial_len - chars.as_str().len(); callback(start..end, unescaped_char); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 30b5f9b34d0..46b90baa585 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -31,7 +31,7 @@ use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::{self, expr_to_string}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticStyledString}; use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -51,7 +51,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, InnerSpan, MultiSpan, Span}; use rustc_target::abi::VariantIdx; -use rustc_trait_selection::traits::misc::can_type_implement_copy; +use rustc_trait_selection::traits::{self, misc::can_type_implement_copy}; use crate::nonstandard_style::{method_context, MethodLateContext}; @@ -764,7 +764,14 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { if ty.is_copy_modulo_regions(cx.tcx.at(item.span), param_env) { return; } - if can_type_implement_copy(cx.tcx, param_env, ty).is_ok() { + if can_type_implement_copy( + cx.tcx, + param_env, + ty, + traits::ObligationCause::misc(item.span, item.hir_id()), + ) + .is_ok() + { cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| { lint.build( "type could implement `Copy`; consider adding `impl \ @@ -1469,17 +1476,17 @@ impl TypeAliasBounds { } } - fn suggest_changing_assoc_types(ty: &hir::Ty<'_>, err: &mut DiagnosticBuilder<'_>) { + fn suggest_changing_assoc_types(ty: &hir::Ty<'_>, err: &mut Diagnostic) { // Access to associates types should use `<T as Bound>::Assoc`, which does not need a // bound. Let's see if this type does that. // We use a HIR visitor to walk the type. use rustc_hir::intravisit::{self, Visitor}; - struct WalkAssocTypes<'a, 'db> { - err: &'a mut DiagnosticBuilder<'db>, + struct WalkAssocTypes<'a> { + err: &'a mut Diagnostic, } - impl<'a, 'db, 'v> Visitor<'v> for WalkAssocTypes<'a, 'db> { - fn visit_qpath(&mut self, qpath: &'v hir::QPath<'v>, id: hir::HirId, span: Span) { + impl Visitor<'_> for WalkAssocTypes<'_> { + fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) { if TypeAliasBounds::is_type_variable_assoc(qpath) { self.err.span_help( span, diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index d8f55292ccd..ac0f4bd8a4d 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -319,7 +319,7 @@ impl LintStore { ) { let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name); if lint_name_only == crate::WARNINGS.name_lower() && level == Level::ForceWarn { - return struct_span_err!( + struct_span_err!( sess, DUMMY_SP, E0602, @@ -327,6 +327,7 @@ impl LintStore { crate::WARNINGS.name_lower() ) .emit(); + return; } let db = match self.check_lint_name(lint_name_only, tool_name, registered_tools) { CheckLintNameResult::Ok(_) => None, @@ -339,7 +340,7 @@ impl LintStore { err.help(&format!("did you mean: `{}`", suggestion)); } - Some(err) + Some(err.forget_guarantee()) } CheckLintNameResult::Tool(result) => match result { Err((Some(_), new_name)) => Some(sess.struct_warn(&format!( @@ -350,13 +351,16 @@ impl LintStore { ))), _ => None, }, - CheckLintNameResult::NoTool => Some(struct_span_err!( - sess, - DUMMY_SP, - E0602, - "unknown lint tool: `{}`", - tool_name.unwrap() - )), + CheckLintNameResult::NoTool => Some( + struct_span_err!( + sess, + DUMMY_SP, + E0602, + "unknown lint tool: `{}`", + tool_name.unwrap() + ) + .forget_guarantee(), + ), }; if let Some(mut db) = db { @@ -765,7 +769,40 @@ pub trait LintContext: Sized { BuiltinLintDiagnostics::NamedAsmLabel(help) => { db.help(&help); db.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information"); - } + }, + BuiltinLintDiagnostics::UnexpectedCfg(span, name, value) => { + let possibilities: Vec<Symbol> = if value.is_some() { + let Some(values) = &sess.parse_sess.check_config.values_valid.get(&name) else { + bug!("it shouldn't be possible to have a diagnostic on a value whose name is not in values"); + }; + values.iter().map(|&s| s).collect() + } else { + let Some(names_valid) = &sess.parse_sess.check_config.names_valid else { + bug!("it shouldn't be possible to have a diagnostic on a name if name checking is not enabled"); + }; + names_valid.iter().map(|s| *s).collect() + }; + + // Show the full list if all possible values for a given name, but don't do it + // for names as the possibilities could be very long + if value.is_some() { + if !possibilities.is_empty() { + let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>(); + possibilities.sort(); + + let possibilities = possibilities.join(", "); + db.note(&format!("expected values for `{name}` are: {possibilities}")); + } else { + db.note(&format!("no expected value for `{name}`")); + } + } + + // Suggest the most probable if we found one + if let Some(best_match) = find_best_match_for_name(&possibilities, value.unwrap_or(name), None) { + let punctuation = if value.is_some() { "\"" } else { "" }; + db.span_suggestion(span, "did you mean", format!("{punctuation}{best_match}{punctuation}"), Applicability::MaybeIncorrect); + } + }, } // Rewrap `db`, and pass control to the user. decorate(LintDiagnosticBuilder::new(db)); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 35c7d885e1d..d7cdb08d817 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -3,7 +3,7 @@ use crate::late::unerased_lint_store; use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::{intravisit, HirId}; use rustc_middle::hir::nested_filter; @@ -150,29 +150,28 @@ impl<'s> LintLevelsBuilder<'s> { fcw_warning, specs, old_src, id_name ); - let decorate_diag_builder = |mut diag_builder: DiagnosticBuilder<'_>| { - diag_builder.span_label(src.span(), "overruled by previous forbid"); + let decorate_diag = |diag: &mut Diagnostic| { + diag.span_label(src.span(), "overruled by previous forbid"); match old_src { LintLevelSource::Default => { - diag_builder.note(&format!( + diag.note(&format!( "`forbid` lint level is the default for {}", id.to_string() )); } LintLevelSource::Node(_, forbid_source_span, reason) => { - diag_builder.span_label(forbid_source_span, "`forbid` level set here"); + diag.span_label(forbid_source_span, "`forbid` level set here"); if let Some(rationale) = reason { - diag_builder.note(rationale.as_str()); + diag.note(rationale.as_str()); } } LintLevelSource::CommandLine(_, _) => { - diag_builder.note("`forbid` lint level was set on command line"); + diag.note("`forbid` lint level was set on command line"); } } - diag_builder.emit(); }; if !fcw_warning { - let diag_builder = struct_span_err!( + let mut diag_builder = struct_span_err!( self.sess, src.span(), E0453, @@ -180,18 +179,20 @@ impl<'s> LintLevelsBuilder<'s> { level.as_str(), src.name(), ); - decorate_diag_builder(diag_builder); + decorate_diag(&mut diag_builder); + diag_builder.emit(); } else { self.struct_lint( FORBIDDEN_LINT_GROUPS, Some(src.span().into()), |diag_builder| { - let diag_builder = diag_builder.build(&format!( + let mut diag_builder = diag_builder.build(&format!( "{}({}) incompatible with previous forbid", level.as_str(), src.name(), )); - decorate_diag_builder(diag_builder); + decorate_diag(&mut diag_builder); + diag_builder.emit(); }, ); } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 69863b5ff82..7182022d252 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -31,6 +31,7 @@ #![feature(box_patterns)] #![feature(crate_visibility_modifier)] #![feature(if_let_guard)] +#![feature(iter_intersperse)] #![feature(iter_order_by)] #![feature(let_else)] #![feature(never_type)] diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 1f834b7212f..e9c62fc4006 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -310,6 +310,7 @@ pub enum BuiltinLintDiagnostics { BreakWithLabelAndLoop(Span), NamedAsmLabel(String), UnicodeTextFlow(Span, String), + UnexpectedCfg(Span, Symbol, Option<Symbol>), } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs index 80dcf99da62..9a7784ca72f 100644 --- a/compiler/rustc_macros/src/session_diagnostic.rs +++ b/compiler/rustc_macros/src/session_diagnostic.rs @@ -232,7 +232,7 @@ impl<'a> SessionDiagnosticDerive<'a> { fn into_diagnostic( self, #sess: &'__session_diagnostic_sess rustc_session::Session - ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess> { + ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, rustc_errors::ErrorReported> { #implementation } } diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 0f10c269a04..dce1b35c6b8 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -243,7 +243,9 @@ impl Collector<'_> { if matches!(lib.kind, NativeLibKind::Framework { .. }) && !is_osx { let msg = "native frameworks are only available on macOS targets"; match span { - Some(span) => struct_span_err!(self.tcx.sess, span, E0455, "{}", msg).emit(), + Some(span) => { + struct_span_err!(self.tcx.sess, span, E0455, "{}", msg).emit(); + } None => self.tcx.sess.err(msg), } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index aaa44a68dc0..e5e0cce198f 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -5,6 +5,7 @@ use crate::rmeta::table::{FixedSizeEncoding, Table}; use crate::rmeta::*; use rustc_ast as ast; +use rustc_ast::ptr::P; use rustc_attr as attr; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; @@ -1076,6 +1077,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { res, vis: ty::Visibility::Public, span: ident.span, + macro_rules: false, }); } } @@ -1087,17 +1089,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { for child_index in children.decode((self, sess)) { if let Some(ident) = self.opt_item_ident(child_index, sess) { let kind = self.def_kind(child_index); - if matches!(kind, DefKind::Macro(..)) { - // FIXME: Macros are currently encoded twice, once as items and once as - // reexports. We ignore the items here and only use the reexports. - continue; - } let def_id = self.local_def_id(child_index); let res = Res::Def(kind, def_id); let vis = self.get_visibility(child_index); let span = self.get_span(child_index, sess); + let macro_rules = match kind { + DefKind::Macro(..) => match self.kind(child_index) { + EntryKind::MacroDef(_, macro_rules) => macro_rules, + _ => unreachable!(), + }, + _ => false, + }; - callback(ModChild { ident, res, vis, span }); + callback(ModChild { ident, res, vis, span, macro_rules }); // For non-re-export structs and variants add their constructors to children. // Re-export lists automatically contain constructors when necessary. @@ -1109,7 +1113,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id); let vis = self.get_visibility(ctor_def_id.index); - callback(ModChild { ident, res: ctor_res, vis, span }); + callback(ModChild { + ident, + res: ctor_res, + vis, + span, + macro_rules: false, + }); } } DefKind::Variant => { @@ -1134,7 +1144,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { vis = ty::Visibility::Restricted(crate_def_id); } } - callback(ModChild { ident, res: ctor_res, vis, span }); + callback(ModChild { + ident, + res: ctor_res, + vis, + span, + macro_rules: false, + }); } _ => {} } @@ -1402,9 +1418,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { tcx.arena.alloc_from_iter(self.root.exported_symbols.decode((self, tcx))) } - fn get_macro(self, id: DefIndex, sess: &Session) -> MacroDef { + fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef { match self.kind(id) { - EntryKind::MacroDef(macro_def) => macro_def.decode((self, sess)), + EntryKind::MacroDef(mac_args, macro_rules) => { + ast::MacroDef { body: P(mac_args.decode((self, sess))), macro_rules } + } _ => bug!(), } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index da8995df1ac..fae76f80c4b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1406,8 +1406,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { EntryKind::Fn(self.lazy(data)) } - hir::ItemKind::Macro(ref macro_def) => { - EntryKind::MacroDef(self.lazy(macro_def.clone())) + hir::ItemKind::Macro(ref macro_def, _) => { + EntryKind::MacroDef(self.lazy(&*macro_def.body), macro_def.macro_rules) } hir::ItemKind::Mod(ref m) => { return self.encode_info_for_mod(item.def_id, m); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index da17d9d4c67..a30cc034c4a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -2,7 +2,7 @@ use decoder::Metadata; use def_path_hash_map::DefPathHashMapRef; use table::{Table, TableBuilder}; -use rustc_ast::{self as ast, MacroDef}; +use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; @@ -350,7 +350,7 @@ enum EntryKind { Fn(Lazy<FnData>), ForeignFn(Lazy<FnData>), Mod(Lazy<[ModChild]>), - MacroDef(Lazy<MacroDef>), + MacroDef(Lazy<ast::MacArgs>, /*macro_rules*/ bool), ProcMacro(MacroKind), Closure, Generator, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index f36847c7781..ec20e888333 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -14,7 +14,6 @@ use rustc_hir::*; use rustc_index::vec::Idx; use rustc_middle::hir::nested_filter; use rustc_span::def_id::StableCrateId; -use rustc_span::hygiene::MacroKind; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; @@ -232,7 +231,7 @@ impl<'hir> Map<'hir> { ItemKind::Static(..) => DefKind::Static, ItemKind::Const(..) => DefKind::Const, ItemKind::Fn(..) => DefKind::Fn, - ItemKind::Macro(..) => DefKind::Macro(MacroKind::Bang), + ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind), ItemKind::Mod(..) => DefKind::Mod, ItemKind::OpaqueTy(..) => DefKind::OpaqueTy, ItemKind::TyAlias(..) => DefKind::TyAlias, diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 294c70f24f8..35e1558600d 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -2,7 +2,7 @@ use std::cmp; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_errors::{DiagnosticBuilder, DiagnosticId}; +use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId}; use rustc_hir::HirId; use rustc_index::vec::IndexVec; use rustc_query_system::ich::StableHashingContext; @@ -186,28 +186,28 @@ impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap { } } -pub struct LintDiagnosticBuilder<'a>(DiagnosticBuilder<'a>); +pub struct LintDiagnosticBuilder<'a>(DiagnosticBuilder<'a, ()>); impl<'a> LintDiagnosticBuilder<'a> { /// Return the inner DiagnosticBuilder, first setting the primary message to `msg`. - pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a> { + pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a, ()> { self.0.set_primary_message(msg); self.0.set_is_lint(); self.0 } /// Create a LintDiagnosticBuilder from some existing DiagnosticBuilder. - pub fn new(err: DiagnosticBuilder<'a>) -> LintDiagnosticBuilder<'a> { + pub fn new(err: DiagnosticBuilder<'a, ()>) -> LintDiagnosticBuilder<'a> { LintDiagnosticBuilder(err) } } -pub fn explain_lint_level_source<'s>( - sess: &'s Session, +pub fn explain_lint_level_source( + sess: &Session, lint: &'static Lint, level: Level, src: LintLevelSource, - err: &mut DiagnosticBuilder<'s>, + err: &mut Diagnostic, ) { let name = lint.name_lower(); match src { @@ -314,10 +314,8 @@ pub fn struct_lint_level<'s, 'd>( return; } } - (Level::Warn, Some(span)) => sess.struct_span_warn(span, ""), - (Level::Warn, None) => sess.struct_warn(""), - (Level::ForceWarn, Some(span)) => sess.struct_span_force_warn(span, ""), - (Level::ForceWarn, None) => sess.struct_force_warn(""), + (Level::Warn | Level::ForceWarn, Some(span)) => sess.struct_span_warn(span, ""), + (Level::Warn | Level::ForceWarn, None) => sess.struct_warn(""), (Level::Deny | Level::Forbid, Some(span)) => { let mut builder = sess.diagnostic().struct_err_lint(""); builder.set_span(span); diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs index 6dcdc58c72d..c8e78747d8e 100644 --- a/compiler/rustc_middle/src/metadata.rs +++ b/compiler/rustc_middle/src/metadata.rs @@ -21,4 +21,6 @@ pub struct ModChild { pub vis: ty::Visibility, /// Span of the item. pub span: Span, + /// A proper `macro_rules` item (not a reexport). + pub macro_rules: bool, } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 7a7d2470444..ff19c33d8e8 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -7,7 +7,7 @@ use crate::ty::{self, DefIdTree, TyCtxt}; use rustc_ast::NodeId; use rustc_attr::{self as attr, ConstStability, Deprecation, Stability}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_feature::GateIssue; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -167,7 +167,7 @@ pub fn deprecation_in_effect(depr: &Deprecation) -> bool { } pub fn deprecation_suggestion( - diag: &mut DiagnosticBuilder<'_>, + diag: &mut Diagnostic, kind: &str, suggestion: Option<Symbol>, span: Span, diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index c5866924eda..31468ce73bf 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -36,7 +36,10 @@ TrivialTypeFoldableAndLiftImpls! { pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>; -pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> { +pub fn struct_error<'tcx>( + tcx: TyCtxtAt<'tcx>, + msg: &str, +) -> DiagnosticBuilder<'tcx, ErrorReported> { struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg) } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index b54418e5201..072e6346cde 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -15,7 +15,7 @@ use crate::ty::subst::SubstsRef; use crate::ty::{self, AdtKind, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_span::symbol::Symbol; @@ -841,7 +841,7 @@ impl ObjectSafetyViolation { } } - pub fn solution(&self, err: &mut DiagnosticBuilder<'_>) { + pub fn solution(&self, err: &mut Diagnostic) { match *self { ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {} ObjectSafetyViolation::Method( diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 934a6a878fe..58cf9fa7a89 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -7,7 +7,7 @@ use crate::ty::{ ProjectionTy, Term, Ty, TyCtxt, TypeAndMut, }; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; @@ -129,7 +129,7 @@ impl<'tcx> Ty<'tcx> { pub fn suggest_arbitrary_trait_bound( generics: &hir::Generics<'_>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, param_name: &str, constraint: &str, ) -> bool { @@ -159,7 +159,7 @@ pub fn suggest_arbitrary_trait_bound( fn suggest_removing_unsized_bound( generics: &hir::Generics<'_>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, param_name: &str, param: &hir::GenericParam<'_>, def_id: Option<DefId>, @@ -266,7 +266,7 @@ fn suggest_removing_unsized_bound( pub fn suggest_constraining_type_param( tcx: TyCtxt<'_>, generics: &hir::Generics<'_>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, param_name: &str, constraint: &str, def_id: Option<DefId>, diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 246c53fdffe..708bd64578c 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -3,7 +3,7 @@ use crate::ty::diagnostics::suggest_constraining_type_param; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt}; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; -use rustc_errors::{pluralize, DiagnosticBuilder}; +use rustc_errors::{pluralize, Diagnostic}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_span::symbol::{sym, Symbol}; @@ -347,7 +347,8 @@ impl<'tcx> Ty<'tcx> { impl<'tcx> TyCtxt<'tcx> { pub fn note_and_explain_type_err( self, - db: &mut DiagnosticBuilder<'_>, + // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. + db: &mut Diagnostic, err: &TypeError<'tcx>, cause: &ObligationCause<'tcx>, sp: Span, @@ -584,7 +585,8 @@ impl<T> Trait<T> for X { fn suggest_constraint( self, - db: &mut DiagnosticBuilder<'_>, + // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. + db: &mut Diagnostic, msg: &str, body_owner_def_id: DefId, proj_ty: &ty::ProjectionTy<'tcx>, @@ -671,7 +673,8 @@ impl<T> Trait<T> for X { /// fn that returns the type. fn expected_projection( self, - db: &mut DiagnosticBuilder<'_>, + // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. + db: &mut Diagnostic, proj_ty: &ty::ProjectionTy<'tcx>, values: &ExpectedFound<Ty<'tcx>>, body_owner_def_id: DefId, @@ -766,7 +769,8 @@ fn foo(&self) -> Self::T { String::new() } /// a return type. This can occur when dealing with `TryStream` (#71035). fn suggest_constraining_opaque_associated_type( self, - db: &mut DiagnosticBuilder<'_>, + // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. + db: &mut Diagnostic, msg: &str, proj_ty: &ty::ProjectionTy<'tcx>, ty: Ty<'tcx>, @@ -802,7 +806,8 @@ fn foo(&self) -> Self::T { String::new() } fn point_at_methods_that_satisfy_associated_type( self, - db: &mut DiagnosticBuilder<'_>, + // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. + db: &mut Diagnostic, assoc_container_id: DefId, current_method_ident: Option<Symbol>, proj_ty_item_def_id: DefId, @@ -857,7 +862,8 @@ fn foo(&self) -> Self::T { String::new() } fn point_at_associated_type( self, - db: &mut DiagnosticBuilder<'_>, + // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. + db: &mut Diagnostic, body_owner_def_id: DefId, found: Ty<'tcx>, ) -> bool { @@ -921,7 +927,8 @@ fn foo(&self) -> Self::T { String::new() } /// type is defined on a supertrait of the one present in the bounds. fn constrain_generic_bound_associated_type_structured_suggestion( self, - db: &mut DiagnosticBuilder<'_>, + // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. + db: &mut Diagnostic, trait_ref: &ty::TraitRef<'tcx>, bounds: hir::GenericBounds<'_>, assoc: &ty::AssocItem, @@ -958,7 +965,8 @@ fn foo(&self) -> Self::T { String::new() } /// associated type to a given type `ty`. fn constrain_associated_type_structured_suggestion( self, - db: &mut DiagnosticBuilder<'_>, + // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. + db: &mut Diagnostic, span: Span, assoc: &ty::AssocItem, assoc_substs: &[ty::GenericArg<'tcx>], diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index d357ac69302..2663ed9049d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -6,7 +6,9 @@ use super::{PatCtxt, PatternError}; use rustc_arena::TypedArena; use rustc_ast::Mutability; -use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{ + error_code, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorReported, +}; use rustc_hir as hir; use rustc_hir::def::*; use rustc_hir::def_id::DefId; @@ -36,7 +38,11 @@ crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { visitor.visit_body(tcx.hir().body(body_id)); } -fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBuilder<'_> { +fn create_e0004( + sess: &Session, + sp: Span, + error_message: String, +) -> DiagnosticBuilder<'_, ErrorReported> { struct_span_err!(sess, sp, E0004, "{}", &error_message) } @@ -281,12 +287,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { /// A path pattern was interpreted as a constant, not a new variable. /// This caused an irrefutable match failure in e.g. `let`. -fn const_not_var( - err: &mut DiagnosticBuilder<'_>, - tcx: TyCtxt<'_>, - pat: &Pat<'_>, - path: &hir::Path<'_>, -) { +fn const_not_var(err: &mut Diagnostic, tcx: TyCtxt<'_>, pat: &Pat<'_>, path: &hir::Path<'_>) { let descr = path.res.descr(); err.span_label( pat.span, @@ -594,7 +595,7 @@ crate fn pattern_not_covered_label( /// Point at the definition of non-covered `enum` variants. fn adt_defined_here<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, ty: Ty<'tcx>, witnesses: &[DeconstructedPat<'p, 'tcx>], ) { diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index a19a3c8b1d5..8731669b109 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -64,7 +64,7 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> { place: &Place<'tcx>, const_item: DefId, location: Location, - decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b>) -> DiagnosticBuilder<'b>, + decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b>) -> DiagnosticBuilder<'b, ()>, ) { // Don't lint on borrowing/assigning when a dereference is involved. // If we 'leave' the temporary via a dereference, we must diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index a517e4879aa..2f88c45a2a3 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1270,7 +1270,10 @@ impl<'v> RootCollector<'_, 'v> { // late-bound regions, since late-bound // regions must appear in the argument // listing. - let main_ret_ty = self.tcx.erase_regions(main_ret_ty.no_bound_vars().unwrap()); + let main_ret_ty = self.tcx.normalize_erasing_regions( + ty::ParamEnv::reveal_all(), + main_ret_ty.no_bound_vars().unwrap(), + ); let start_instance = Instance::resolve( self.tcx, diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 4cdd83c0acd..3212fc39fb9 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -3,7 +3,9 @@ use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Token, TokenKind}; use rustc_ast::tokenstream::{Spacing, TokenStream}; use rustc_ast::util::unicode::contains_text_flow_control_chars; -use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError, PResult}; +use rustc_errors::{ + error_code, Applicability, DiagnosticBuilder, ErrorReported, FatalError, PResult, +}; use rustc_lexer::unescape::{self, Mode}; use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_session::lint::builtin::{ @@ -127,7 +129,7 @@ impl<'a> StringReader<'a> { to_pos: BytePos, m: &str, c: char, - ) -> DiagnosticBuilder<'a> { + ) -> DiagnosticBuilder<'a, ErrorReported> { self.sess .span_diagnostic .struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c))) diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index a41956c58f0..c7d166319ea 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -144,7 +144,7 @@ pub(crate) fn emit_unescape_error( c.escape_default().to_string(), Applicability::MachineApplicable, ) - .emit() + .emit(); } EscapeError::BareCarriageReturn => { let msg = if mode.in_double_quotes() { @@ -292,16 +292,18 @@ pub(crate) fn emit_unescape_error( .span_label(span, "must have at most 6 hex digits") .emit(); } - EscapeError::UnclosedUnicodeEscape => handler - .struct_span_err(span, "unterminated unicode escape") - .span_label(span, "missing a closing `}`") - .span_suggestion_verbose( - span.shrink_to_hi(), - "terminate the unicode escape", - "}".to_string(), - Applicability::MaybeIncorrect, - ) - .emit(), + EscapeError::UnclosedUnicodeEscape => { + handler + .struct_span_err(span, "unterminated unicode escape") + .span_label(span, "missing a closing `}`") + .span_suggestion_verbose( + span.shrink_to_hi(), + "terminate the unicode escape", + "}".to_string(), + Applicability::MaybeIncorrect, + ) + .emit(); + } EscapeError::NoBraceInUnicodeEscape => { let msg = "incorrect unicode escape sequence"; let mut diag = handler.struct_span_err(span, msg); @@ -347,7 +349,7 @@ pub(crate) fn emit_unescape_error( } EscapeError::ZeroChars => { let msg = "empty character literal"; - handler.struct_span_err(span, msg).span_label(span, msg).emit() + handler.struct_span_err(span, msg).span_label(span, msg).emit(); } EscapeError::LoneSlash => { let msg = "invalid trailing slash in literal"; diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index c2a75d2bc2c..1d63b79adc5 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -3,7 +3,7 @@ use super::StringReader; use crate::token; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_span::{symbol::kw, BytePos, Pos, Span}; #[rustfmt::skip] // for line breaks @@ -336,7 +336,7 @@ pub(super) fn check_for_substitution<'a>( reader: &StringReader<'a>, pos: BytePos, ch: char, - err: &mut DiagnosticBuilder<'a>, + err: &mut Diagnostic, ) -> Option<token::TokenKind> { let Some(&(_u_char, u_name, ascii_char)) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch) else { return None; diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index ca92d6b7fd0..379e47077ea 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -3,7 +3,7 @@ use rustc_ast as ast; use rustc_ast::attr; use rustc_ast::token::{self, Nonterminal}; use rustc_ast_pretty::pprust; -use rustc_errors::{error_code, DiagnosticBuilder, PResult}; +use rustc_errors::{error_code, Diagnostic, PResult}; use rustc_span::{sym, BytePos, Span}; use std::convert::TryInto; @@ -147,7 +147,7 @@ impl<'a> Parser<'a> { fn annotate_following_item_if_applicable( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, span: Span, attr_type: OuterAttributeType, ) -> Option<Span> { @@ -165,7 +165,7 @@ impl<'a> Parser<'a> { loop { // skip any other attributes, we want the item if snapshot.token.kind == token::Pound { - if let Err(mut err) = snapshot.parse_attribute(InnerAttrPolicy::Permitted) { + if let Err(err) = snapshot.parse_attribute(InnerAttrPolicy::Permitted) { err.cancel(); return Some(replacement_span); } @@ -206,7 +206,7 @@ impl<'a> Parser<'a> { ); return None; } - Err(mut item_err) => { + Err(item_err) => { item_err.cancel(); } Ok(None) => {} @@ -412,12 +412,12 @@ impl<'a> Parser<'a> { fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { match self.parse_unsuffixed_lit() { Ok(lit) => return Ok(ast::NestedMetaItem::Literal(lit)), - Err(ref mut err) => err.cancel(), + Err(err) => err.cancel(), } match self.parse_meta_item() { Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)), - Err(ref mut err) => err.cancel(), + Err(err) => err.cancel(), } let found = pprust::token_to_string(&self.token); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index def23005fbe..f1c2dcf10e8 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -16,7 +16,7 @@ use rustc_ast::{ }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{pluralize, struct_span_err}; +use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorReported}; use rustc_errors::{Applicability, DiagnosticBuilder, Handler, PResult}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, Ident}; @@ -53,7 +53,11 @@ pub enum Error { } impl Error { - fn span_err(self, sp: impl Into<MultiSpan>, handler: &Handler) -> DiagnosticBuilder<'_> { + fn span_err( + self, + sp: impl Into<MultiSpan>, + handler: &Handler, + ) -> DiagnosticBuilder<'_, ErrorReported> { match self { Error::UselessDocComment => { let mut err = struct_span_err!( @@ -151,11 +155,19 @@ impl AttemptLocalParseRecovery { } impl<'a> Parser<'a> { - pub(super) fn span_err<S: Into<MultiSpan>>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> { + pub(super) fn span_err<S: Into<MultiSpan>>( + &self, + sp: S, + err: Error, + ) -> DiagnosticBuilder<'a, ErrorReported> { err.span_err(sp, self.diagnostic()) } - pub fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { + pub fn struct_span_err<S: Into<MultiSpan>>( + &self, + sp: S, + m: &str, + ) -> DiagnosticBuilder<'a, ErrorReported> { self.sess.span_diagnostic.struct_span_err(sp, m) } @@ -171,7 +183,7 @@ impl<'a> Parser<'a> { self.sess.source_map().span_to_snippet(span) } - pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a> { + pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a, ErrorReported> { let mut err = self.struct_span_err( self.token.span, &format!("expected identifier, found {}", super::token_descr(&self.token)), @@ -393,7 +405,7 @@ impl<'a> Parser<'a> { Err(err) } - fn check_too_many_raw_str_terminators(&mut self, err: &mut DiagnosticBuilder<'_>) -> bool { + fn check_too_many_raw_str_terminators(&mut self, err: &mut Diagnostic) -> bool { match (&self.prev_token.kind, &self.token.kind) { ( TokenKind::Literal(Lit { @@ -461,12 +473,12 @@ impl<'a> Parser<'a> { tail.could_be_bare_literal = true; Ok(tail) } - (Err(mut err), Ok(tail)) => { + (Err(err), Ok(tail)) => { // We have a block tail that contains a somehow valid type ascription expr. err.cancel(); Ok(tail) } - (Err(mut snapshot_err), Err(err)) => { + (Err(snapshot_err), Err(err)) => { // We don't know what went wrong, emit the normal error. snapshot_err.cancel(); self.consume_block(token::Brace, ConsumeClosingDelim::Yes); @@ -483,7 +495,7 @@ impl<'a> Parser<'a> { pub fn maybe_annotate_with_ascription( &mut self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, maybe_expected_semicolon: bool, ) { if let Some((sp, likely_path)) = self.last_type_ascription.take() { @@ -537,7 +549,7 @@ impl<'a> Parser<'a> { /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, /// passes through any errors encountered. Used for error recovery. pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) { - if let Err(ref mut err) = + if let Err(err) = self.parse_seq_to_before_tokens(kets, SeqSep::none(), TokenExpectType::Expect, |p| { Ok(p.parse_token_tree()) }) @@ -703,7 +715,7 @@ impl<'a> Parser<'a> { *self = snapshot; } } - Err(mut err) => { + Err(err) => { // We couldn't parse generic parameters, unlikely to be a turbofish. Rely on // generic parse error instead. err.cancel(); @@ -717,7 +729,7 @@ impl<'a> Parser<'a> { /// encounter a parse error when encountering the first `,`. pub(super) fn check_mistyped_turbofish_with_multiple_type_params( &mut self, - mut e: DiagnosticBuilder<'a>, + mut e: DiagnosticBuilder<'a, ErrorReported>, expr: &mut P<Expr>, ) -> PResult<'a, ()> { if let ExprKind::Binary(binop, _, _) = &expr.kind { @@ -744,14 +756,14 @@ impl<'a> Parser<'a> { self.mk_expr_err(expr.span.to(self.prev_token.span)); return Ok(()); } - Err(mut err) => { + Err(err) => { *expr = self.mk_expr_err(expr.span); err.cancel(); } } } } - Err(mut err) => { + Err(err) => { err.cancel(); } _ => {} @@ -767,7 +779,7 @@ impl<'a> Parser<'a> { /// parenthesising the leftmost comparison. fn attempt_chained_comparison_suggestion( &mut self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, inner_op: &Expr, outer_op: &Spanned<AssocOp>, ) -> bool /* advanced the cursor */ { @@ -821,7 +833,7 @@ impl<'a> Parser<'a> { enclose(r1.span, r2.span); true } - Err(mut expr_err) => { + Err(expr_err) => { expr_err.cancel(); *self = snapshot; false @@ -838,7 +850,7 @@ impl<'a> Parser<'a> { enclose(l1.span, r1.span); true } - Err(mut expr_err) => { + Err(expr_err) => { expr_err.cancel(); *self = snapshot; false @@ -890,7 +902,7 @@ impl<'a> Parser<'a> { "comparison operators cannot be chained", ); - let suggest = |err: &mut DiagnosticBuilder<'_>| { + let suggest = |err: &mut Diagnostic| { err.span_suggestion_verbose( op.span.shrink_to_lo(), TURBOFISH_SUGGESTION_STR, @@ -938,7 +950,7 @@ impl<'a> Parser<'a> { // `ExprKind::Err` placeholder. mk_err_expr(self, inner_op.span.to(self.prev_token.span)) } - Err(mut expr_err) => { + Err(expr_err) => { expr_err.cancel(); // Not entirely sure now, but we bubble the error up with the // suggestion. @@ -1439,7 +1451,7 @@ impl<'a> Parser<'a> { pub(super) fn recover_closing_delimiter( &mut self, tokens: &[TokenKind], - mut err: DiagnosticBuilder<'a>, + mut err: DiagnosticBuilder<'a, ErrorReported>, ) -> PResult<'a, bool> { let mut pos = None; // We want to use the last closing delim that would apply. @@ -1637,7 +1649,7 @@ impl<'a> Parser<'a> { pub(super) fn parameter_without_type( &mut self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, pat: P<ast::Pat>, require_name: bool, first_param: bool, @@ -1810,7 +1822,7 @@ impl<'a> Parser<'a> { } } - pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a> { + pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a, ErrorReported> { let (span, msg) = match (&self.token.kind, self.subparser_name) { (&token::Eof, Some(origin)) => { let sp = self.sess.source_map().next_point(self.prev_token.span); @@ -1946,17 +1958,14 @@ impl<'a> Parser<'a> { Ok(expr) } - fn recover_const_param_decl( - &mut self, - ty_generics: Option<&Generics>, - ) -> PResult<'a, Option<GenericArg>> { + fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option<GenericArg> { let snapshot = self.clone(); let param = match self.parse_const_param(vec![]) { Ok(param) => param, - Err(mut err) => { + Err(err) => { err.cancel(); *self = snapshot; - return Err(err); + return None; } }; let mut err = @@ -1977,7 +1986,7 @@ impl<'a> Parser<'a> { } let value = self.mk_expr_err(param.span()); err.emit(); - return Ok(Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }))); + Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })) } pub fn recover_const_param_declaration( @@ -1985,8 +1994,8 @@ impl<'a> Parser<'a> { ty_generics: Option<&Generics>, ) -> PResult<'a, Option<GenericArg>> { // We have to check for a few different cases. - if let Ok(arg) = self.recover_const_param_decl(ty_generics) { - return Ok(arg); + if let Some(arg) = self.recover_const_param_decl(ty_generics) { + return Ok(Some(arg)); } // We haven't consumed `const` yet. @@ -2019,7 +2028,7 @@ impl<'a> Parser<'a> { pub fn recover_const_arg( &mut self, start: Span, - mut err: DiagnosticBuilder<'a>, + mut err: DiagnosticBuilder<'a, ErrorReported>, ) -> PResult<'a, GenericArg> { let is_op = AssocOp::from_token(&self.token) .and_then(|op| { @@ -2085,7 +2094,7 @@ impl<'a> Parser<'a> { return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })); } } - Err(mut err) => { + Err(err) => { err.cancel(); } } @@ -2099,7 +2108,7 @@ impl<'a> Parser<'a> { pub(super) fn incorrect_move_async_order_found( &self, move_async_span: Span, - ) -> DiagnosticBuilder<'a> { + ) -> DiagnosticBuilder<'a, ErrorReported> { let mut err = self.struct_span_err(move_async_span, "the order of `move` and `async` is incorrect"); err.span_suggestion_verbose( @@ -2139,7 +2148,7 @@ impl<'a> Parser<'a> { Err(mut err) => { self.bump(); // Skip the `:`. match self.parse_pat_no_top_alt(expected) { - Err(mut inner_err) => { + Err(inner_err) => { // Carry on as if we had not done anything, callers will emit a // reasonable error. inner_err.cancel(); @@ -2246,7 +2255,7 @@ impl<'a> Parser<'a> { // suggestion-enhanced error here rather than choking on the comma later. let comma_span = self.token.span; self.bump(); - if let Err(mut err) = self.skip_pat_list() { + if let Err(err) = self.skip_pat_list() { // We didn't expect this to work anyway; we just wanted to advance to the // end of the comma-sequence so we know the span to suggest parenthesizing. err.cancel(); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 7cb8c35b868..c6919779ffd 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -17,7 +17,7 @@ use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, Lit, UnOp use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind}; use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; use rustc_ast_pretty::pprust; -use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported, PResult}; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::edition::LATEST_STABLE_EDITION; @@ -684,7 +684,7 @@ impl<'a> Parser<'a> { let parser_snapshot_before_type = self.clone(); let cast_expr = match self.parse_as_cast_ty() { Ok(rhs) => mk_expr(self, lhs, rhs), - Err(mut type_err) => { + Err(type_err) => { // Rewind to before attempting to parse the type with generics, to recover // from situations like `x as usize < y` in which we first tried to parse // `usize < y` as a type with generic arguments. @@ -717,7 +717,7 @@ impl<'a> Parser<'a> { .emit(); return Ok(expr); } - Err(mut err) => { + Err(err) => { err.cancel(); *self = snapshot; } @@ -773,7 +773,7 @@ impl<'a> Parser<'a> { expr } - Err(mut path_err) => { + Err(path_err) => { // Couldn't parse as a path, return original error and parser state. path_err.cancel(); *self = parser_snapshot_after_type; @@ -1127,7 +1127,7 @@ impl<'a> Parser<'a> { snapshot: Option<(Self, ExprKind)>, ) -> Option<P<Expr>> { match (seq.as_mut(), snapshot) { - (Err(ref mut err), Some((mut snapshot, ExprKind::Path(None, path)))) => { + (Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => { let name = pprust::path_to_string(&path); snapshot.bump(); // `(` match snapshot.parse_struct_fields(path, false, token::Paren) { @@ -1138,11 +1138,12 @@ impl<'a> Parser<'a> { let close_paren = self.prev_token.span; let span = lo.to(self.prev_token.span); if !fields.is_empty() { - err.cancel(); - let mut err = self.struct_span_err( + let replacement_err = self.struct_span_err( span, "invalid `struct` delimiters or `fn` call arguments", ); + mem::replace(err, replacement_err).cancel(); + err.multipart_suggestion( &format!("if `{}` is a struct, use braces as delimiters", name), vec![ @@ -1166,7 +1167,9 @@ impl<'a> Parser<'a> { return Some(self.mk_expr_err(span)); } Ok(_) => {} - Err(mut err) => err.emit(), + Err(mut err) => { + err.emit(); + } } } _ => {} @@ -1622,9 +1625,11 @@ impl<'a> Parser<'a> { }; if let Some(expr) = expr { if matches!(expr.kind, ExprKind::Err) { - self.diagnostic() - .delay_span_bug(self.token.span, &"invalid interpolated expression"); - return self.diagnostic().struct_dummy(); + let mut err = self + .diagnostic() + .struct_span_err(self.token.span, &"invalid interpolated expression"); + err.downgrade_to_delayed_bug(); + return err; } } } @@ -1816,6 +1821,7 @@ impl<'a> Parser<'a> { err } else { self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind)) + .forget_guarantee() }; err.span_label(sp, format!("invalid suffix `{}`", suf)); err.emit(); @@ -1876,7 +1882,7 @@ impl<'a> Parser<'a> { *self = snapshot; Some(self.mk_expr_err(arr.span)) } - Err(mut e) => { + Err(e) => { e.cancel(); None } @@ -2097,9 +2103,9 @@ impl<'a> Parser<'a> { fn error_missing_if_then_block( &self, if_span: Span, - err: Option<DiagnosticBuilder<'a>>, + err: Option<DiagnosticBuilder<'a, ErrorReported>>, binop_span: Option<Span>, - ) -> DiagnosticBuilder<'a> { + ) -> DiagnosticBuilder<'a, ErrorReported> { let msg = "this `if` expression has a condition, but no block"; let mut err = if let Some(mut err) = err { @@ -2379,7 +2385,7 @@ impl<'a> Parser<'a> { return Some(err(self, stmts)); } } - Err(mut err) => { + Err(err) => { err.cancel(); } } @@ -2396,7 +2402,7 @@ impl<'a> Parser<'a> { } // We couldn't parse either yet another statement missing it's // enclosing block nor the next arm's pattern or closing brace. - Err(mut stmt_err) => { + Err(stmt_err) => { stmt_err.cancel(); *self = start_snapshot; break; @@ -2653,7 +2659,7 @@ impl<'a> Parser<'a> { let mut base = ast::StructRest::None; let mut recover_async = false; - let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| { + let mut async_block_err = |e: &mut Diagnostic, span: Span| { recover_async = true; e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later"); e.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION)); diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 4b57aa1f24a..1b9eeab0298 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -130,7 +130,7 @@ impl<'a> Parser<'a> { // FIXME - try to continue parsing other generics? return Ok((None, TrailingToken::None)); } - Err(mut err) => { + Err(err) => { err.cancel(); // FIXME - maybe we should overwrite 'self' outside of `collect_tokens`? *this = snapshot; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 20ca8a99ab7..bd349e89482 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -13,7 +13,7 @@ use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, Vari use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind}; use rustc_ast::{MacArgs, MacCall, MacDelimiter}; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_err, Applicability, PResult, StashKey}; +use rustc_errors::{struct_span_err, Applicability, ErrorReported, PResult, StashKey}; use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; use rustc_span::lev_distance::lev_distance; use rustc_span::source_map::{self, Span}; @@ -801,7 +801,7 @@ impl<'a> Parser<'a> { before_where_clause_span: Span, after_predicates: &[WherePredicate], after_where_clause_span: Span, - ) { + ) -> ErrorReported { let mut err = self.struct_span_err(after_where_clause_span, "where clause not allowed here"); if !after_predicates.is_empty() { @@ -1114,7 +1114,7 @@ impl<'a> Parser<'a> { // Only try to recover if this is implementing a trait for a type let mut impl_info = match self.parse_item_impl(attrs, defaultness) { Ok(impl_info) => impl_info, - Err(mut recovery_error) => { + Err(recovery_error) => { // Recovery failed, raise the "expected identifier" error recovery_error.cancel(); return Err(err); @@ -1476,7 +1476,9 @@ impl<'a> Parser<'a> { // after the comma self.eat(&token::Comma); // `check_trailing_angle_brackets` already emitted a nicer error - err.cancel(); + // NOTE(eddyb) this was `.cancel()`, but `err` + // gets returned, so we can't fully defuse it. + err.downgrade_to_delayed_bug(); } } } @@ -2073,7 +2075,7 @@ impl<'a> Parser<'a> { if let Ok(snippet) = self.span_to_snippet(sp) { let current_vis = match self.parse_visibility(FollowedByType::No) { Ok(v) => v, - Err(mut d) => { + Err(d) => { d.cancel(); return Err(err); } @@ -2216,7 +2218,7 @@ impl<'a> Parser<'a> { // If this is a C-variadic argument and we hit an error, return the error. Err(err) if this.token == token::DotDotDot => return Err(err), // Recover from attempting to parse the argument as a type without pattern. - Err(mut err) => { + Err(err) => { err.cancel(); *this = parser_snapshot_before_ty; this.recover_arg_parse()? @@ -2358,7 +2360,7 @@ impl<'a> Parser<'a> { match self .parse_outer_attributes() .and_then(|_| self.parse_self_param()) - .map_err(|mut e| e.cancel()) + .map_err(|e| e.cancel()) { Ok(Some(_)) => "method", _ => "function", diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 6d534bece46..d8e6d5037bb 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -32,7 +32,7 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_errors::PResult; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported, FatalError}; use rustc_session::parse::ParseSess; use rustc_span::source_map::{MultiSpan, Span, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -849,7 +849,7 @@ impl<'a> Parser<'a> { v.push(t); continue; } - Err(mut e) => { + Err(e) => { // Parsing failed, therefore it must be something more serious // than just a missing separator. expect_err.emit(); @@ -877,7 +877,7 @@ impl<'a> Parser<'a> { fn recover_missing_braces_around_closure_body( &mut self, closure_spans: ClosureSpans, - mut expect_err: DiagnosticBuilder<'_>, + mut expect_err: DiagnosticBuilder<'_, ErrorReported>, ) -> PResult<'a, ()> { let initial_semicolon = self.token.span; @@ -1429,7 +1429,7 @@ impl<'a> Parser<'a> { crate fn make_unclosed_delims_error( unmatched: UnmatchedBrace, sess: &ParseSess, -) -> Option<DiagnosticBuilder<'_>> { +) -> Option<DiagnosticBuilder<'_, ErrorReported>> { // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to // `unmatched_braces` only for error recovery in the `Parser`. let found_delim = unmatched.found_delim?; diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index ac3123c40e3..d4129871145 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -8,7 +8,7 @@ use rustc_ast::{ PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax, }; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported, PResult}; use rustc_span::source_map::{respan, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; @@ -655,7 +655,7 @@ impl<'a> Parser<'a> { fn fatal_unexpected_non_pat( &mut self, - mut err: DiagnosticBuilder<'a>, + err: DiagnosticBuilder<'a, ErrorReported>, expected: Expected, ) -> PResult<'a, P<Pat>> { err.cancel(); @@ -722,7 +722,7 @@ impl<'a> Parser<'a> { // Ensure the user doesn't receive unhelpful unexpected token errors self.bump(); if self.is_pat_range_end_start(0) { - let _ = self.parse_pat_range_end().map_err(|mut e| e.cancel()); + let _ = self.parse_pat_range_end().map_err(|e| e.cancel()); } self.error_inclusive_range_with_extra_equals(span_with_eq); @@ -886,7 +886,7 @@ impl<'a> Parser<'a> { let mut fields = Vec::new(); let mut etc = false; let mut ate_comma = true; - let mut delayed_err: Option<DiagnosticBuilder<'a>> = None; + let mut delayed_err: Option<DiagnosticBuilder<'a, ErrorReported>> = None; let mut etc_span = None; while self.token != token::CloseDelim(token::Brace) { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 48502112e3a..b5857e05970 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -394,7 +394,7 @@ impl<'a> Parser<'a> { debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)"); match self.parse_angle_args(ty_generics) { Ok(args) => Ok(args), - Err(mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => { + Err(e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => { // Swap `self` with our backup of the parser state before attempting to parse // generic arguments. let snapshot = mem::replace(self, snapshot.unwrap()); diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 965e6a6ca3f..6b195285243 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -18,7 +18,7 @@ use rustc_ast::{ }; use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt}; use rustc_ast::{StmtKind, DUMMY_NODE_ID}; -use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported, PResult}; use rustc_span::source_map::{BytePos, Span}; use rustc_span::symbol::{kw, sym}; @@ -296,7 +296,7 @@ impl<'a> Parser<'a> { // extra noise. init } - (Err(mut init_err), Some((snapshot, _, ty_err))) => { + (Err(init_err), Some((snapshot, _, ty_err))) => { // init error, ty error init_err.cancel(); // Couldn't parse the type nor the initializer, only raise the type error and @@ -414,7 +414,10 @@ impl<'a> Parser<'a> { Ok(block) } - fn error_block_no_opening_brace_msg(&mut self, msg: &str) -> DiagnosticBuilder<'a> { + fn error_block_no_opening_brace_msg( + &mut self, + msg: &str, + ) -> DiagnosticBuilder<'a, ErrorReported> { let sp = self.token.span; let mut e = self.struct_span_err(sp, msg); let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon; @@ -449,7 +452,7 @@ impl<'a> Parser<'a> { ); } } - Err(mut e) => { + Err(e) => { self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); e.cancel(); } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 566b77a5e9e..0b01f9e927f 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -345,7 +345,8 @@ impl<'a> Parser<'a> { let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()); let bounds = self.parse_generic_bounds_common(allow_plus, None)?; if lt_no_plus { - self.struct_span_err(lo, "lifetime in trait object type must be followed by `+`").emit() + self.struct_span_err(lo, "lifetime in trait object type must be followed by `+`") + .emit(); } Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3d69e8ba4e4..68efbbb74c3 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1951,7 +1951,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { // Historically we've run more checks on non-exported than exported macros, // so this lets us continue to run them while maintaining backwards compatibility. // In the long run, the checks should be harmonized. - if let ItemKind::Macro(ref macro_def) = item.kind { + if let ItemKind::Macro(ref macro_def, _) = item.kind { let def_id = item.def_id.to_def_id(); if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) { check_non_exported_macro_for_invalid_attrs(self.tcx, item); @@ -2095,7 +2095,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { rustc_errors::Applicability::MachineApplicable, ); } - err.emit() + err.emit(); } } } diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 2b11f6b0c1d..0fdbdb7b08d 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -219,7 +219,9 @@ impl<'tcx> CheckConstVisitor<'tcx> { required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect(); match missing_gates.as_slice() { - [] => struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(), + [] => { + struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(); + } [missing_primary, ref missing_secondary @ ..] => { let mut err = feature_err(&tcx.sess.parse_sess, *missing_primary, span, &msg); diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs index d7dde157864..b2129ce9f24 100644 --- a/compiler/rustc_passes/src/intrinsicck.rs +++ b/compiler/rustc_passes/src/intrinsicck.rs @@ -118,7 +118,7 @@ impl<'tcx> ExprVisitor<'tcx> { err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from))) .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to))); } - err.emit() + err.emit(); } fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 48594e73f5b..3dd9995fa00 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -564,7 +564,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { // privacy and mark them reachable. DefKind::Macro(_) => { let item = self.tcx.hir().expect_item(def_id); - if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }) = item.kind { + if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind { if vis.is_accessible_from(module.to_def_id(), self.tcx) { self.update(def_id, level); } @@ -686,7 +686,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } } } - hir::ItemKind::Macro(ref macro_def) => { + hir::ItemKind::Macro(ref macro_def, _) => { self.update_reachability_from_macro(item.def_id, macro_def); } hir::ItemKind::ForeignMod { items, .. } => { diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index b1ff1e15a9d..91b6ea03835 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -7,7 +7,7 @@ use crate::query::caches::QueryCache; use crate::query::{QueryCacheStore, QueryContext, QueryState}; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::{DiagnosticBuilder, ErrorReported}; use std::fmt::Debug; use std::hash::Hash; @@ -27,7 +27,7 @@ pub struct QueryVtable<CTX: QueryContext, K, V> { pub compute: fn(CTX::DepContext, K) -> V, pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>, - pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V, + pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_, ErrorReported>) -> V, pub try_load_from_disk: Option<fn(CTX, SerializedDepNodeIndex) -> Option<V>>, } diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 4588403925e..260fc3bff44 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -4,7 +4,7 @@ use crate::query::{QueryContext, QueryStackFrame}; use rustc_hir::def::DefKind; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, Handler, Level}; +use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, ErrorReported, Handler, Level}; use rustc_session::Session; use rustc_span::Span; @@ -530,7 +530,7 @@ pub fn deadlock<CTX: QueryContext>(tcx: CTX, registry: &rayon_core::Registry) { pub(crate) fn report_cycle<'a>( sess: &'a Session, CycleError { usage, cycle: stack }: CycleError, -) -> DiagnosticBuilder<'a> { +) -> DiagnosticBuilder<'a, ErrorReported> { assert!(!stack.is_empty()); let fix_span = |span: Span, query: &QueryStackFrame| { diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 77e1fd3f2cc..23df0d4dcd4 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -14,7 +14,7 @@ use rustc_data_structures::profiling::TimingGuard; use rustc_data_structures::sharded::{get_shard_index_by_hash, Sharded}; use rustc_data_structures::sync::{Lock, LockGuard}; use rustc_data_structures::thin_vec::ThinVec; -use rustc_errors::{DiagnosticBuilder, FatalError}; +use rustc_errors::{DiagnosticBuilder, ErrorReported, FatalError}; use rustc_session::Session; use rustc_span::{Span, DUMMY_SP}; use std::cell::Cell; @@ -143,7 +143,7 @@ where fn mk_cycle<CTX, V, R>( tcx: CTX, error: CycleError, - handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V, + handle_cycle_error: fn(CTX, DiagnosticBuilder<'_, ErrorReported>) -> V, cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>, ) -> R where diff --git a/compiler/rustc_resolve/src/access_levels.rs b/compiler/rustc_resolve/src/access_levels.rs index 60cc4248edc..61a9b644cb8 100644 --- a/compiler/rustc_resolve/src/access_levels.rs +++ b/compiler/rustc_resolve/src/access_levels.rs @@ -133,7 +133,7 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> { ast::ItemKind::Impl(..) => return, // Only exported `macro_rules!` items are public, but they always are - ast::ItemKind::MacroDef(..) => { + ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => { let is_macro_export = item.attrs.iter().any(|attr| attr.has_name(sym::macro_export)); if is_macro_export { Some(AccessLevel::Public) } else { None } @@ -155,7 +155,8 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> { | ast::ItemKind::Struct(..) | ast::ItemKind::Union(..) | ast::ItemKind::Trait(..) - | ast::ItemKind::TraitAlias(..) => { + | ast::ItemKind::TraitAlias(..) + | ast::ItemKind::MacroDef(..) => { if item.vis.kind.is_pub() { self.prev_level } else { diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 3fa9343c399..2c3ddae9cb4 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -940,7 +940,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { /// Builds the reduced graph for a single item in an external crate. fn build_reduced_graph_for_external_crate_res(&mut self, child: ModChild) { let parent = self.parent_scope.module; - let ModChild { ident, res, vis, span } = child; + let ModChild { ident, res, vis, span, macro_rules } = child; let res = res.expect_non_local(); let expansion = self.parent_scope.expansion; // Record primary definitions. @@ -972,7 +972,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { _, ) => self.r.define(parent, ident, ValueNS, (res, vis, span, expansion)), Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => { - self.r.define(parent, ident, MacroNS, (res, vis, span, expansion)) + if !macro_rules { + self.r.define(parent, ident, MacroNS, (res, vis, span, expansion)) + } } Res::Def( DefKind::TyParam @@ -1068,8 +1070,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { .emit(); } } - let ill_formed = - |span| struct_span_err!(self.r.session, span, E0466, "bad macro import").emit(); + let ill_formed = |span| { + struct_span_err!(self.r.session, span, E0466, "bad macro import").emit(); + }; match attr.meta() { Some(meta) => match meta.kind { MetaItemKind::Word => { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 9a2fb3b86e2..b366473cb30 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -3,7 +3,7 @@ use std::ptr; use rustc_ast::{self as ast, Path}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorReported}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind}; @@ -110,7 +110,7 @@ impl<'a> Resolver<'a> { &self, span: Span, resolution_error: ResolutionError<'_>, - ) -> DiagnosticBuilder<'_> { + ) -> DiagnosticBuilder<'_, ErrorReported> { match resolution_error { ResolutionError::GenericParamsFromOuterFunction(outer_res, has_generic_params) => { let mut err = struct_span_err!( @@ -624,7 +624,10 @@ impl<'a> Resolver<'a> { } } - crate fn report_vis_error(&self, vis_resolution_error: VisResolutionError<'_>) { + crate fn report_vis_error( + &self, + vis_resolution_error: VisResolutionError<'_>, + ) -> ErrorReported { match vis_resolution_error { VisResolutionError::Relative2018(span, path) => { let mut err = self.session.struct_span_err( @@ -1031,7 +1034,7 @@ impl<'a> Resolver<'a> { crate fn unresolved_macro_suggestions( &mut self, - err: &mut DiagnosticBuilder<'a>, + err: &mut Diagnostic, macro_kind: MacroKind, parent_scope: &ParentScope<'a>, ident: Ident, @@ -1120,7 +1123,7 @@ impl<'a> Resolver<'a> { crate fn add_typo_suggestion( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, suggestion: Option<TypoSuggestion>, span: Span, ) -> bool { @@ -1817,7 +1820,7 @@ fn find_span_immediately_after_crate_name( crate fn show_candidates( definitions: &rustc_hir::definitions::Definitions, session: &Session, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, // This is `None` if all placement locations are inside expansions use_placement_span: Option<Span>, candidates: &[ImportSuggestion], diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 5e21161f2e0..bf570fb0f80 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1399,14 +1399,22 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut reexports = Vec::new(); module.for_each_child(self.r, |_, ident, _, binding| { - // Filter away ambiguous imports and anything that has def-site hygiene. - // FIXME: Implement actual cross-crate hygiene. - let is_good_import = - binding.is_import() && !binding.is_ambiguity() && !ident.span.from_expansion(); - if is_good_import || binding.is_macro_def() { + // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules` + // into the crate root to actual `NameBindingKind::Import`. + if binding.is_import() + || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true)) + { let res = binding.res().expect_non_local(); - if res != def::Res::Err { - reexports.push(ModChild { ident, res, vis: binding.vis, span: binding.span }); + // Ambiguous imports are treated as errors at this point and are + // not exposed to other crates (see #36837 for more details). + if res != def::Res::Err && !binding.is_ambiguity() { + reexports.push(ModChild { + ident, + res, + vis: binding.vis, + span: binding.span, + macro_rules: false, + }); } } }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 9ac3e6e22bd..91695257137 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2001,13 +2001,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // into a single one. let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node); - parent_err.cancel(); - err.message = take(&mut parent_err.message); err.code = take(&mut parent_err.code); err.children = take(&mut parent_err.children); - drop(parent_err); + parent_err.cancel(); let def_id = this.parent_scope.module.nearest_parent_mod(); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index f20cf29cc89..b71776c1615 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -12,7 +12,9 @@ use rustc_ast::{ }; use rustc_ast_pretty::pprust::path_segment_to_string; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{ + pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorReported, +}; use rustc_hir as hir; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; @@ -133,7 +135,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { span: Span, source: PathSource<'_>, res: Option<Res>, - ) -> (DiagnosticBuilder<'a>, Vec<ImportSuggestion>) { + ) -> (DiagnosticBuilder<'a, ErrorReported>, Vec<ImportSuggestion>) { let ident_span = path.last().map_or(span, |ident| ident.ident.span); let ns = source.namespace(); let is_expected = &|res| source.is_expected(res); @@ -606,11 +608,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { (err, candidates) } - fn detect_assoct_type_constraint_meant_as_path( - &self, - base_span: Span, - err: &mut DiagnosticBuilder<'_>, - ) { + fn detect_assoct_type_constraint_meant_as_path(&self, base_span: Span, err: &mut Diagnostic) { let Some(ty) = self.diagnostic_metadata.current_type_path else { return; }; let TyKind::Path(_, path) = &ty.kind else { return; }; for segment in &path.segments { @@ -675,11 +673,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`. - fn restrict_assoc_type_in_where_clause( - &mut self, - span: Span, - err: &mut DiagnosticBuilder<'_>, - ) -> bool { + fn restrict_assoc_type_in_where_clause(&mut self, span: Span, err: &mut Diagnostic) -> bool { // Detect that we are actually in a `where` predicate. let (bounded_ty, bounds, where_span) = if let Some(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { @@ -875,7 +869,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { /// Returns `true` if able to provide context-dependent help. fn smart_resolve_context_dependent_help( &mut self, - err: &mut DiagnosticBuilder<'a>, + err: &mut Diagnostic, span: Span, source: PathSource<'_>, res: Res, @@ -885,7 +879,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let ns = source.namespace(); let is_expected = &|res| source.is_expected(res); - let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.kind { + let path_sep = |err: &mut Diagnostic, expr: &Expr| match expr.kind { ExprKind::Field(_, ident) => { err.span_suggestion( expr.span, @@ -908,7 +902,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { _ => false, }; - let find_span = |source: &PathSource<'_>, err: &mut DiagnosticBuilder<'_>| { + let find_span = |source: &PathSource<'_>, err: &mut Diagnostic| { match source { PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. })) | PathSource::TupleStruct(span, _) => { @@ -1066,7 +1060,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { }) .unwrap_or(false) { - err.delay_as_bug(); + err.downgrade_to_delayed_bug(); // We already suggested changing `:` into `::` during parsing. return false; } @@ -1435,7 +1429,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { start.to(sm.next_point(start)) } - fn type_ascription_suggestion(&self, err: &mut DiagnosticBuilder<'_>, base_span: Span) -> bool { + fn type_ascription_suggestion(&self, err: &mut Diagnostic, base_span: Span) -> bool { let sm = self.r.session.source_map(); let base_snippet = sm.span_to_snippet(base_span); if let Some(&sp) = self.diagnostic_metadata.current_type_ascription.last() { @@ -1472,7 +1466,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .borrow_mut() .insert(colon_sp) { - err.delay_as_bug(); + err.downgrade_to_delayed_bug(); } } if let Ok(base_snippet) = base_snippet { @@ -1577,7 +1571,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { /// Adds a suggestion for using an enum's variant when an enum is used instead. fn suggest_using_enum_variant( &mut self, - err: &mut DiagnosticBuilder<'a>, + err: &mut Diagnostic, source: PathSource<'_>, def_id: DefId, span: Span, @@ -1825,7 +1819,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { &self, spans: Vec<Span>, count: usize, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { struct_span_err!( self.tcx.sess, spans, @@ -1910,7 +1904,8 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { /// Returns whether to add `'static` lifetime to the suggested lifetime list. crate fn report_elision_failure( &mut self, - db: &mut DiagnosticBuilder<'_>, + // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`. + db: &mut Diagnostic, params: &[ElisionFailureInfo], ) -> bool { let mut m = String::new(); @@ -2059,7 +2054,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { crate fn add_missing_lifetime_specifiers_label( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, mut spans_with_counts: Vec<(Span, usize)>, lifetime_names: &FxHashSet<Symbol>, lifetime_spans: Vec<Span>, @@ -2090,7 +2085,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { } let suggest_existing = - |err: &mut DiagnosticBuilder<'_>, + |err: &mut Diagnostic, name: &str, formatters: Vec<Option<Box<dyn Fn(&str) -> String>>>| { if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) = @@ -2174,7 +2169,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { Applicability::MaybeIncorrect, ); }; - let suggest_new = |err: &mut DiagnosticBuilder<'_>, suggs: Vec<Option<String>>| { + let suggest_new = |err: &mut Diagnostic, suggs: Vec<Option<String>>| { for missing in self.missing_named_lifetime_spots.iter().rev() { let mut introduce_suggestion = vec![]; let msg; diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 2f0ad60709d..23a8189f62f 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -9,7 +9,7 @@ use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot}; use rustc_ast::walk_list; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefIdMap, LocalDefId}; @@ -1572,6 +1572,7 @@ fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shado name, orig.kind.desc() ) + .forget_guarantee() } else { // shadowing involving a label is only a warning, due to issues with // labels and lifetimes not being macro-hygienic. @@ -1873,7 +1874,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // or from `fn rah<'a>(T<'a>)` to `fn rah(T<'_>)` fn suggest_eliding_single_use_lifetime( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, def_id: DefId, lifetime: &hir::Lifetime, ) { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 04b0a18b12b..4823b889207 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -40,7 +40,7 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorReported}; use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; use rustc_hir::def::Namespace::*; use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes}; @@ -713,7 +713,7 @@ struct PrivacyError<'a> { } struct UseError<'a> { - err: DiagnosticBuilder<'a>, + err: DiagnosticBuilder<'a, ErrorReported>, /// Candidates which user could `use` to access the missing type. candidates: Vec<ImportSuggestion>, /// The `DefId` of the module to place the use-statements in. @@ -845,10 +845,6 @@ impl<'a> NameBinding<'a> { ) } - fn is_macro_def(&self) -> bool { - matches!(self.kind, NameBindingKind::Res(Res::Def(DefKind::Macro(..), _), _)) - } - fn macro_kind(&self) -> Option<MacroKind> { self.res().macro_kind() } @@ -990,6 +986,9 @@ pub struct Resolver<'a> { crate_loader: CrateLoader<'a>, macro_names: FxHashSet<Ident>, builtin_macros: FxHashMap<Symbol, BuiltinMacroState>, + /// A small map keeping true kinds of built-in macros that appear to be fn-like on + /// the surface (`macro` items in libcore), but are actually attributes or derives. + builtin_macro_kinds: FxHashMap<LocalDefId, MacroKind>, registered_attrs: FxHashSet<Ident>, registered_tools: RegisteredTools, macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>, @@ -1261,6 +1260,10 @@ impl ResolverAstLowering for Resolver<'_> { def_id } + + fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind { + self.builtin_macro_kinds.get(&def_id).copied().unwrap_or(MacroKind::Bang) + } } impl<'a> Resolver<'a> { @@ -1381,6 +1384,7 @@ impl<'a> Resolver<'a> { crate_loader: CrateLoader::new(session, metadata_loader, crate_name), macro_names: FxHashSet::default(), builtin_macros: Default::default(), + builtin_macro_kinds: Default::default(), registered_attrs, registered_tools, macro_use_prelude: FxHashMap::default(), @@ -3169,7 +3173,7 @@ impl<'a> Resolver<'a> { /// ``` fn add_suggestion_for_rename_of_use( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, name: Symbol, import: &Import<'_>, binding_span: Span, @@ -3248,7 +3252,7 @@ impl<'a> Resolver<'a> { /// as characters expected by span manipulations won't be present. fn add_suggestion_for_duplicate_nested_use( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, import: &Import<'_>, binding_span: Span, ) { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 89c2a0c74bd..e34d3e605ec 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1209,7 +1209,13 @@ impl<'a> Resolver<'a> { // while still taking everything else from the source code. // If we already loaded this builtin macro, give a better error message than 'no such builtin macro'. match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) { - BuiltinMacroState::NotYetSeen(ext) => result.kind = ext, + BuiltinMacroState::NotYetSeen(ext) => { + result.kind = ext; + if item.id != ast::DUMMY_NODE_ID { + self.builtin_macro_kinds + .insert(self.local_def_id(item.id), result.macro_kind()); + } + } BuiltinMacroState::AlreadySeen(span) => { struct_span_err!( self.session, diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs index 3bb1d2ff357..8f50f445719 100644 --- a/compiler/rustc_save_analysis/src/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -416,7 +416,7 @@ impl<'hir> Sig for hir::Item<'hir> { Ok(sig) } - hir::ItemKind::Macro(_) => { + hir::ItemKind::Macro(..) => { let mut text = "macro".to_owned(); let name = self.ident.to_string(); text.push_str(&name); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 7a0d9a212c9..f9b75690e37 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -8,7 +8,7 @@ use crate::search_paths::SearchPath; use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; use crate::{early_error, early_warn, Session}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::impl_stable_hash_via_hash; use rustc_target::abi::{Align, TargetDataLayout}; @@ -1023,34 +1023,30 @@ pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig /// The parsed `--check-cfg` options pub struct CheckCfg<T = String> { - /// Set if `names()` checking is enabled - pub names_checked: bool, - /// The union of all `names()` - pub names_valid: FxHashSet<T>, - /// The set of names for which `values()` was used - pub values_checked: FxHashSet<T>, - /// The set of all (name, value) pairs passed in `values()` - pub values_valid: FxHashSet<(T, T)>, + /// The set of all `names()`, if None no name checking is performed + pub names_valid: Option<FxHashSet<T>>, + /// The set of all `values()` + pub values_valid: FxHashMap<T, FxHashSet<T>>, } impl<T> Default for CheckCfg<T> { fn default() -> Self { - CheckCfg { - names_checked: false, - names_valid: FxHashSet::default(), - values_checked: FxHashSet::default(), - values_valid: FxHashSet::default(), - } + CheckCfg { names_valid: Default::default(), values_valid: Default::default() } } } impl<T> CheckCfg<T> { fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> { CheckCfg { - names_checked: self.names_checked, - names_valid: self.names_valid.iter().map(|a| f(a)).collect(), - values_checked: self.values_checked.iter().map(|a| f(a)).collect(), - values_valid: self.values_valid.iter().map(|(a, b)| (f(a), f(b))).collect(), + names_valid: self + .names_valid + .as_ref() + .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()), + values_valid: self + .values_valid + .iter() + .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect())) + .collect(), } } } @@ -1090,17 +1086,23 @@ impl CrateCheckConfig { sym::doctest, sym::feature, ]; - for &name in WELL_KNOWN_NAMES { - self.names_valid.insert(name); + if let Some(names_valid) = &mut self.names_valid { + for &name in WELL_KNOWN_NAMES { + names_valid.insert(name); + } } } /// Fills a `CrateCheckConfig` with configuration names and values that are actually active. pub fn fill_actual(&mut self, cfg: &CrateConfig) { for &(k, v) in cfg { - self.names_valid.insert(k); + if let Some(names_valid) = &mut self.names_valid { + names_valid.insert(k); + } if let Some(v) = v { - self.values_valid.insert((k, v)); + self.values_valid.entry(k).and_modify(|values| { + values.insert(v); + }); } } } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 7113f9b0a2f..e287764a52a 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -7,7 +7,7 @@ use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; -use rustc_errors::{error_code, Applicability, DiagnosticBuilder}; +use rustc_errors::{error_code, Applicability, Diagnostic, DiagnosticBuilder, ErrorReported}; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; use rustc_span::hygiene::ExpnId; @@ -82,7 +82,7 @@ pub fn feature_err<'a>( feature: Symbol, span: impl Into<MultiSpan>, explain: &str, -) -> DiagnosticBuilder<'a> { +) -> DiagnosticBuilder<'a, ErrorReported> { feature_err_issue(sess, feature, span, GateIssue::Language, explain) } @@ -96,7 +96,7 @@ pub fn feature_err_issue<'a>( span: impl Into<MultiSpan>, issue: GateIssue, explain: &str, -) -> DiagnosticBuilder<'a> { +) -> DiagnosticBuilder<'a, ErrorReported> { let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658)); if let Some(n) = find_feature_issue(feature, issue) { @@ -243,7 +243,7 @@ impl ParseSess { /// Extend an error with a suggestion to wrap an expression with parentheses to allow the /// parser to continue parsing the following operation as part of the same expression. - pub fn expr_parentheses_needed(&self, err: &mut DiagnosticBuilder<'_>, span: Span) { + pub fn expr_parentheses_needed(&self, err: &mut Diagnostic, span: Span) { err.multipart_suggestion( "parentheses are required to parse this as an expression", vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), ")".to_string())], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 9bcdd7f3da6..b72be735ce4 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -19,7 +19,7 @@ use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter; use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; -use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorReported}; +use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorReported}; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; use rustc_span::edition::Edition; @@ -221,7 +221,7 @@ enum DiagnosticBuilderMethod { pub trait SessionDiagnostic<'a> { /// Write out as a diagnostic out of `sess`. #[must_use] - fn into_diagnostic(self, sess: &'a Session) -> DiagnosticBuilder<'a>; + fn into_diagnostic(self, sess: &'a Session) -> DiagnosticBuilder<'a, ErrorReported>; } /// Diagnostic message ID, used by `Session.one_time_diagnostics` to avoid @@ -303,37 +303,39 @@ impl Session { self.crate_types.set(crate_types).expect("`crate_types` was initialized twice") } - pub fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'_> { - self.diagnostic().struct_span_warn(sp, msg) - } - pub fn struct_span_force_warn<S: Into<MultiSpan>>( + pub fn struct_span_warn<S: Into<MultiSpan>>( &self, sp: S, msg: &str, - ) -> DiagnosticBuilder<'_> { - self.diagnostic().struct_span_force_warn(sp, msg) + ) -> DiagnosticBuilder<'_, ()> { + self.diagnostic().struct_span_warn(sp, msg) } pub fn struct_span_warn_with_code<S: Into<MultiSpan>>( &self, sp: S, msg: &str, code: DiagnosticId, - ) -> DiagnosticBuilder<'_> { + ) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_span_warn_with_code(sp, msg, code) } - pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_> { + pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_warn(msg) } - pub fn struct_force_warn(&self, msg: &str) -> DiagnosticBuilder<'_> { - self.diagnostic().struct_force_warn(msg) - } - pub fn struct_span_allow<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'_> { + pub fn struct_span_allow<S: Into<MultiSpan>>( + &self, + sp: S, + msg: &str, + ) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_span_allow(sp, msg) } - pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_> { + pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_allow(msg) } - pub fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'_> { + pub fn struct_span_err<S: Into<MultiSpan>>( + &self, + sp: S, + msg: &str, + ) -> DiagnosticBuilder<'_, ErrorReported> { self.diagnostic().struct_span_err(sp, msg) } pub fn struct_span_err_with_code<S: Into<MultiSpan>>( @@ -341,17 +343,25 @@ impl Session { sp: S, msg: &str, code: DiagnosticId, - ) -> DiagnosticBuilder<'_> { + ) -> DiagnosticBuilder<'_, ErrorReported> { self.diagnostic().struct_span_err_with_code(sp, msg, code) } // FIXME: This method should be removed (every error should have an associated error code). - pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> { + pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorReported> { self.diagnostic().struct_err(msg) } - pub fn struct_err_with_code(&self, msg: &str, code: DiagnosticId) -> DiagnosticBuilder<'_> { + pub fn struct_err_with_code( + &self, + msg: &str, + code: DiagnosticId, + ) -> DiagnosticBuilder<'_, ErrorReported> { self.diagnostic().struct_err_with_code(msg, code) } - pub fn struct_span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'_> { + pub fn struct_span_fatal<S: Into<MultiSpan>>( + &self, + sp: S, + msg: &str, + ) -> DiagnosticBuilder<'_, ErrorReported> { self.diagnostic().struct_span_fatal(sp, msg) } pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>( @@ -359,10 +369,10 @@ impl Session { sp: S, msg: &str, code: DiagnosticId, - ) -> DiagnosticBuilder<'_> { + ) -> DiagnosticBuilder<'_, ErrorReported> { self.diagnostic().struct_span_fatal_with_code(sp, msg, code) } - pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_> { + pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_, ErrorReported> { self.diagnostic().struct_fatal(msg) } @@ -396,7 +406,7 @@ impl Session { pub fn err(&self, msg: &str) { self.diagnostic().err(msg) } - pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) { + pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorReported { err.into_diagnostic(self).emit() } #[inline] @@ -467,7 +477,7 @@ impl Session { pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { self.diagnostic().span_note_without_error(sp, msg) } - pub fn struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_> { + pub fn struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_note_without_error(msg) } @@ -478,9 +488,9 @@ impl Session { /// Analogous to calling methods on the given `DiagnosticBuilder`, but /// deduplicates on lint ID, span (if any), and message for this `Session` - fn diag_once<'a, 'b>( - &'a self, - diag_builder: &'b mut DiagnosticBuilder<'a>, + fn diag_once( + &self, + diag: &mut Diagnostic, method: DiagnosticBuilderMethod, msg_id: DiagnosticMessageId, message: &str, @@ -491,39 +501,33 @@ impl Session { if fresh { match method { DiagnosticBuilderMethod::Note => { - diag_builder.note(message); + diag.note(message); } DiagnosticBuilderMethod::SpanNote => { let span = span_maybe.expect("`span_note` needs a span"); - diag_builder.span_note(span, message); + diag.span_note(span, message); } } } } - pub fn diag_span_note_once<'a, 'b>( - &'a self, - diag_builder: &'b mut DiagnosticBuilder<'a>, + pub fn diag_span_note_once( + &self, + diag: &mut Diagnostic, msg_id: DiagnosticMessageId, span: Span, message: &str, ) { - self.diag_once( - diag_builder, - DiagnosticBuilderMethod::SpanNote, - msg_id, - message, - Some(span), - ); + self.diag_once(diag, DiagnosticBuilderMethod::SpanNote, msg_id, message, Some(span)); } - pub fn diag_note_once<'a, 'b>( - &'a self, - diag_builder: &'b mut DiagnosticBuilder<'a>, + pub fn diag_note_once( + &self, + diag: &mut Diagnostic, msg_id: DiagnosticMessageId, message: &str, ) { - self.diag_once(diag_builder, DiagnosticBuilderMethod::Note, msg_id, message, None); + self.diag_once(diag, DiagnosticBuilderMethod::Note, msg_id, message, None); } #[inline] diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 8b76f3f7151..0f6997054b9 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -14,6 +14,7 @@ use crate::traits::{ PredicateObligations, SelectionContext, }; //use rustc_data_structures::fx::FxHashMap; +use rustc_errors::Diagnostic; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::CRATE_HIR_ID; use rustc_infer::infer::TyCtxtInferExt; @@ -50,7 +51,7 @@ pub struct OverlapResult<'tcx> { pub involves_placeholder: bool, } -pub fn add_placeholder_note(err: &mut rustc_errors::DiagnosticBuilder<'_>) { +pub fn add_placeholder_note(err: &mut Diagnostic) { err.note( "this behavior recently changed as a result of a bug fix; \ see rust-lang/rust#56105 for details", diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 8746d66ebb6..f26f32aabda 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -12,7 +12,9 @@ use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCod use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; +use rustc_errors::{ + pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorReported, +}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; @@ -100,7 +102,7 @@ pub trait InferCtxtExt<'tcx> { expected_args: Vec<ArgKind>, found_args: Vec<ArgKind>, is_closure: bool, - ) -> DiagnosticBuilder<'tcx>; + ) -> DiagnosticBuilder<'tcx, ErrorReported>; } impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { @@ -1017,7 +1019,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { expected_args: Vec<ArgKind>, found_args: Vec<ArgKind>, is_closure: bool, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let kind = if is_closure { "closure" } else { "function" }; let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { @@ -1174,7 +1176,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> { fn report_similar_impl_candidates( &self, impl_candidates: Vec<ImplCandidate<'tcx>>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, ); /// Gets the parent trait chain start @@ -1186,11 +1188,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> { /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait /// with the same path as `trait_ref`, a help message about /// a probable version mismatch is added to `err` - fn note_version_mismatch( - &self, - err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::PolyTraitRef<'tcx>, - ); + fn note_version_mismatch(&self, err: &mut Diagnostic, trait_ref: &ty::PolyTraitRef<'tcx>); /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the /// `trait_ref`. @@ -1215,35 +1213,26 @@ trait InferCtxtPrivExt<'hir, 'tcx> { pred: ty::PolyTraitRef<'tcx>, ) -> bool; - fn note_obligation_cause( - &self, - err: &mut DiagnosticBuilder<'tcx>, - obligation: &PredicateObligation<'tcx>, - ); + fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>); fn suggest_unsized_bound_if_applicable( &self, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>, ); fn annotate_source_of_ambiguity( &self, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut Diagnostic, impls: &[DefId], predicate: ty::Predicate<'tcx>, ); - fn maybe_suggest_unsized_generics( - &self, - err: &mut DiagnosticBuilder<'tcx>, - span: Span, - node: Node<'hir>, - ); + fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'hir>); fn maybe_indirection_for_unsized( &self, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut Diagnostic, item: &'hir Item<'hir>, param: &'hir GenericParam<'hir>, ) -> bool; @@ -1572,7 +1561,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { fn report_similar_impl_candidates( &self, impl_candidates: Vec<ImplCandidate<'tcx>>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, ) { if impl_candidates.is_empty() { return; @@ -1649,11 +1638,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait /// with the same path as `trait_ref`, a help message about /// a probable version mismatch is added to `err` - fn note_version_mismatch( - &self, - err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::PolyTraitRef<'tcx>, - ) { + fn note_version_mismatch(&self, err: &mut Diagnostic, trait_ref: &ty::PolyTraitRef<'tcx>) { let get_trait_impl = |trait_def_id| { self.tcx.find_map_relevant_impl(trait_def_id, trait_ref.skip_binder().self_ty(), Some) }; @@ -1944,7 +1929,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { fn annotate_source_of_ambiguity( &self, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut Diagnostic, impls: &[DefId], predicate: ty::Predicate<'tcx>, ) { @@ -1977,7 +1962,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { // Avoid complaining about other inference issues for expressions like // `42 >> 1`, where the types are still `{integer}`, but we want to // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too? - err.cancel(); + // NOTE(eddyb) this was `.cancel()`, but `err` + // is borrowed, so we can't fully defuse it. + err.downgrade_to_delayed_bug(); return; } let post = if post.len() > 4 { @@ -2088,11 +2075,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { }) } - fn note_obligation_cause( - &self, - err: &mut DiagnosticBuilder<'tcx>, - obligation: &PredicateObligation<'tcx>, - ) { + fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>) { // First, attempt to add note to this error with an async-await-specific // message, and fall back to regular note otherwise. if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { @@ -2110,7 +2093,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { fn suggest_unsized_bound_if_applicable( &self, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>, ) { let (pred, item_def_id, span) = match ( @@ -2139,7 +2122,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { fn maybe_suggest_unsized_generics<'hir>( &self, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut Diagnostic, span: Span, node: Node<'hir>, ) { @@ -2206,7 +2189,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { fn maybe_indirection_for_unsized<'hir>( &self, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut Diagnostic, item: &'hir Item<'hir>, param: &'hir GenericParam<'hir>, ) -> bool { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index e162e943e36..c4fbd25b833 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -10,7 +10,8 @@ use crate::traits::normalize_projection_type; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ - error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style, + error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, + ErrorReported, Style, }; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -47,7 +48,7 @@ pub enum GeneratorInteriorOrUpvar { pub trait InferCtxtExt<'tcx> { fn suggest_restricting_param_bound( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, body_id: hir::HirId, ); @@ -55,28 +56,23 @@ pub trait InferCtxtExt<'tcx> { fn suggest_dereferences( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, ); - fn get_closure_name( - &self, - def_id: DefId, - err: &mut DiagnosticBuilder<'_>, - msg: &str, - ) -> Option<String>; + fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option<String>; fn suggest_fn_call( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, ); fn suggest_add_reference_to_arg( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, has_custom_message: bool, ) -> bool; @@ -84,27 +80,23 @@ pub trait InferCtxtExt<'tcx> { fn suggest_remove_reference( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, ); - fn suggest_remove_await( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'_>, - ); + fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic); fn suggest_change_mut( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, ); fn suggest_semicolon_removal( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, span: Span, trait_pred: ty::PolyTraitPredicate<'tcx>, ); @@ -113,7 +105,7 @@ pub trait InferCtxtExt<'tcx> { fn suggest_impl_trait( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, span: Span, obligation: &PredicateObligation<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, @@ -121,7 +113,7 @@ pub trait InferCtxtExt<'tcx> { fn point_at_returns_when_relevant( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>, ); @@ -131,11 +123,11 @@ pub trait InferCtxtExt<'tcx> { found_span: Option<Span>, expected_ref: ty::PolyTraitRef<'tcx>, found: ty::PolyTraitRef<'tcx>, - ) -> DiagnosticBuilder<'tcx>; + ) -> DiagnosticBuilder<'tcx, ErrorReported>; fn suggest_fully_qualified_path( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, def_id: DefId, span: Span, trait_ref: DefId, @@ -143,13 +135,13 @@ pub trait InferCtxtExt<'tcx> { fn maybe_note_obligation_cause_for_async_await( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>, ) -> bool; fn note_obligation_cause_for_async_await( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, interior_or_upvar_span: GeneratorInteriorOrUpvar, interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>, inner_generator_body: Option<&hir::Body<'tcx>>, @@ -163,7 +155,7 @@ pub trait InferCtxtExt<'tcx> { fn note_obligation_cause_code<T>( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, predicate: &T, param_env: ty::ParamEnv<'tcx>, cause_code: &ObligationCauseCode<'tcx>, @@ -172,12 +164,12 @@ pub trait InferCtxtExt<'tcx> { ) where T: fmt::Display; - fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>); + fn suggest_new_overflow_limit(&self, err: &mut Diagnostic); /// Suggest to await before try: future? => future.await? fn suggest_await_before_try( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, span: Span, @@ -202,7 +194,7 @@ fn suggest_restriction<'tcx>( tcx: TyCtxt<'tcx>, generics: &hir::Generics<'tcx>, msg: &str, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, fn_sig: Option<&hir::FnSig<'_>>, projection: Option<&ty::ProjectionTy<'_>>, trait_pred: ty::PolyTraitPredicate<'tcx>, @@ -329,7 +321,7 @@ fn suggest_restriction<'tcx>( impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_restricting_param_bound( &self, - mut err: &mut DiagnosticBuilder<'_>, + mut err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, body_id: hir::HirId, ) { @@ -493,7 +485,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_dereferences( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, ) { // It only make sense when suggesting dereferences for arguments @@ -549,26 +541,20 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// Given a closure's `DefId`, return the given name of the closure. /// /// This doesn't account for reassignments, but it's only used for suggestions. - fn get_closure_name( - &self, - def_id: DefId, - err: &mut DiagnosticBuilder<'_>, - msg: &str, - ) -> Option<String> { - let get_name = - |err: &mut DiagnosticBuilder<'_>, kind: &hir::PatKind<'_>| -> Option<String> { - // Get the local name of this closure. This can be inaccurate because - // of the possibility of reassignment, but this should be good enough. - match &kind { - hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => { - Some(format!("{}", name)) - } - _ => { - err.note(&msg); - None - } + fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option<String> { + let get_name = |err: &mut Diagnostic, kind: &hir::PatKind<'_>| -> Option<String> { + // Get the local name of this closure. This can be inaccurate because + // of the possibility of reassignment, but this should be good enough. + match &kind { + hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => { + Some(format!("{}", name)) } - }; + _ => { + err.note(&msg); + None + } + } + }; let hir = self.tcx.hir(); let hir_id = hir.local_def_id_to_hir_id(def_id.as_local()?); @@ -590,7 +576,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_fn_call( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, ) { let self_ty = match trait_pred.self_ty().no_bound_vars() { @@ -683,7 +669,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_add_reference_to_arg( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, poly_trait_pred: ty::PolyTraitPredicate<'tcx>, has_custom_message: bool, ) -> bool { @@ -817,7 +803,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_remove_reference( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, ) { let span = obligation.cause.span; @@ -874,11 +860,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } - fn suggest_remove_await( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'_>, - ) { + fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) { let span = obligation.cause.span; if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() { @@ -936,7 +918,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_change_mut( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, ) { let points_at_arg = matches!( @@ -1012,7 +994,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_semicolon_removal( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, span: Span, trait_pred: ty::PolyTraitPredicate<'tcx>, ) { @@ -1063,7 +1045,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// emitted. fn suggest_impl_trait( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, span: Span, obligation: &PredicateObligation<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, @@ -1256,7 +1238,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn point_at_returns_when_relevant( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>, ) { match obligation.cause.code().peel_derives() { @@ -1290,7 +1272,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { found_span: Option<Span>, expected_ref: ty::PolyTraitRef<'tcx>, found: ty::PolyTraitRef<'tcx>, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { crate fn build_fn_sig_string<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, @@ -1345,7 +1327,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_fully_qualified_path( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, def_id: DefId, span: Span, trait_ref: DefId, @@ -1411,7 +1393,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// Returns `true` if an async-await specific note was added to the diagnostic. fn maybe_note_obligation_cause_for_async_await( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>, ) -> bool { debug!( @@ -1639,7 +1621,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// `maybe_note_obligation_cause_for_async_await`'s documentation comment. fn note_obligation_cause_for_async_await( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, interior_or_upvar_span: GeneratorInteriorOrUpvar, interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>, inner_generator_body: Option<&hir::Body<'tcx>>, @@ -1896,7 +1878,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn note_obligation_cause_code<T>( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, predicate: &T, param_env: ty::ParamEnv<'tcx>, cause_code: &ObligationCauseCode<'tcx>, @@ -2133,7 +2115,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let ty = parent_trait_ref.skip_binder().self_ty(); if parent_trait_ref.references_error() { - err.cancel(); + // NOTE(eddyb) this was `.cancel()`, but `err` + // is borrowed, so we can't fully defuse it. + err.downgrade_to_delayed_bug(); return; } @@ -2412,7 +2396,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } - fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) { + fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) { let suggested_limit = match self.tcx.recursion_limit() { Limit(0) => Limit(2), limit => limit * 2, @@ -2427,7 +2411,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_await_before_try( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, span: Span, @@ -2615,7 +2599,7 @@ impl NextTypeParamName for &[hir::GenericParam<'_>] { } fn suggest_trait_object_return_type_alternatives( - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, ret_ty: Span, trait_obj: &str, is_object_safe: bool, diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index b23dce8a581..c293708dcc9 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -20,6 +20,7 @@ pub fn can_type_implement_copy<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, self_type: Ty<'tcx>, + cause: ObligationCause<'tcx>, ) -> Result<(), CopyImplementationError<'tcx>> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt().enter(|infcx| { @@ -49,7 +50,19 @@ pub fn can_type_implement_copy<'tcx>( continue; } let span = tcx.def_span(field.did); - let cause = ObligationCause::dummy_with_span(span); + // FIXME(compiler-errors): This gives us better spans for bad + // projection types like in issue-50480. + // If the ADT has substs, point to the cause we are given. + // If it does not, then this field probably doesn't normalize + // to begin with, and point to the bad field's span instead. + let cause = if field + .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did)) + .has_param_types_or_consts() + { + cause.clone() + } else { + ObligationCause::dummy_with_span(span) + }; let ctx = traits::FulfillmentContext::new(); match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) { Ok(ty) => { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5b646c6d447..8bcb1ccb584 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -29,7 +29,7 @@ use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::ErrorReported; +use rustc_errors::{Diagnostic, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::LateBoundRegionConversionTime; @@ -64,7 +64,7 @@ pub enum IntercrateAmbiguityCause { impl IntercrateAmbiguityCause { /// Emits notes when the overlap is caused by complex intercrate ambiguities. /// See #23980 for details. - pub fn add_intercrate_ambiguity_hint(&self, err: &mut rustc_errors::DiagnosticBuilder<'_>) { + pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diagnostic) { err.note(&self.intercrate_ambiguity_hint()); } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 38a6220082f..acf1c976afc 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -450,7 +450,7 @@ fn report_conflicting_impls( sg.has_errored = true; if overlap.with_impl.is_local() || !tcx.orphan_check_crate(()).contains(&impl_def_id) { let err = struct_span_err!(tcx.sess, impl_span, E0119, ""); - decorate(LintDiagnosticBuilder::new(err)); + decorate(LintDiagnosticBuilder::new(err.forget_guarantee())); } else { tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check"); } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index b6e653c0eea..f800e7a1402 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -1,4 +1,4 @@ -use rustc_errors::DiagnosticBuilder; +use rustc_errors::Diagnostic; use rustc_span::Span; use smallvec::smallvec; use smallvec::SmallVec; @@ -43,12 +43,7 @@ impl<'tcx> TraitAliasExpansionInfo<'tcx> { /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate /// trait aliases. - pub fn label_with_exp_info( - &self, - diag: &mut DiagnosticBuilder<'_>, - top_label: &str, - use_desc: &str, - ) { + pub fn label_with_exp_info(&self, diag: &mut Diagnostic, top_label: &str, use_desc: &str) { diag.span_label(self.top().1, top_label); if self.path.len() > 1 { for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) { diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 05ff7f818c7..b16bf33f06a 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -6,7 +6,7 @@ use crate::astconv::{ use crate::errors::AssocTypeBindingNotAllowed; use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs}; use rustc_ast::ast::ParamKindOrd; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorReported}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -49,7 +49,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } - let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut DiagnosticBuilder<'_>| { + let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut Diagnostic| { let suggestions = vec![ (arg.span().shrink_to_lo(), String::from("{ ")), (arg.span().shrink_to_hi(), String::from(" }")), diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index dbe7ddeb6a8..efa50375c95 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -15,7 +15,7 @@ use crate::middle::resolve_lifetime as rl; use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{struct_span_err, Applicability, ErrorReported, FatalError}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported, FatalError}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -2618,7 +2618,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, constrained_regions: FxHashSet<ty::BoundRegionKind>, referenced_regions: FxHashSet<ty::BoundRegionKind>, - generate_err: impl Fn(&str) -> rustc_errors::DiagnosticBuilder<'tcx>, + generate_err: impl Fn(&str) -> DiagnosticBuilder<'tcx, ErrorReported>, ) { for br in referenced_regions.difference(&constrained_regions) { let br_name = match *br { diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 3701b255b75..9529e1528a8 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -1,6 +1,6 @@ use crate::check::coercion::{AsCoercionSite, CoerceMany}; use crate::check::{Diverges, Expectation, FnCtxt, Needs}; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::{self as hir, ExprKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::traits::Obligation; @@ -132,7 +132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &cause, Some(&arm.body), arm_ty, - Some(&mut |err: &mut DiagnosticBuilder<'_>| { + Some(&mut |err: &mut Diagnostic| { let can_coerce_to_return_ty = match self.ret_coercion.as_ref() { Some(ret_coercion) if self.in_tail_expr => { let ret_ty = ret_coercion.borrow().expected_ty(); diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 679cac0b82a..d5187c109e3 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -2,7 +2,7 @@ use super::method::MethodCallee; use super::{Expectation, FnCtxt, TupleArgumentsFlag}; use crate::type_error_struct; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::def::{Namespace, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; @@ -277,7 +277,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// likely intention is to call the closure, suggest `(||{})()`. (#55851) fn identify_bad_closure_def_and_call( &self, - err: &mut DiagnosticBuilder<'a>, + err: &mut Diagnostic, hir_id: hir::HirId, callee_node: &hir::ExprKind<'_>, callee_span: Span, @@ -304,7 +304,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// likely intention is to create an array containing tuples. fn maybe_suggest_bad_array_definition( &self, - err: &mut DiagnosticBuilder<'a>, + err: &mut Diagnostic, call_expr: &'tcx hir::Expr<'tcx>, callee_expr: &'tcx hir::Expr<'tcx>, ) -> bool { diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 57076d97246..cd24969bf28 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -179,7 +179,7 @@ fn make_invalid_casting_error<'a, 'tcx>( expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, fcx: &FnCtxt<'a, 'tcx>, -) -> DiagnosticBuilder<'a> { +) -> DiagnosticBuilder<'a, ErrorReported> { type_error_struct!( sess, span, diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 30ae382de42..7dca95ebdd6 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -37,14 +37,16 @@ pub fn check_wf_new(tcx: TyCtxt<'_>) { pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { match tcx.sess.target.is_abi_supported(abi) { Some(true) => (), - Some(false) => struct_span_err!( - tcx.sess, - span, - E0570, - "`{}` is not a supported ABI for the current target", - abi - ) - .emit(), + Some(false) => { + struct_span_err!( + tcx.sess, + span, + E0570, + "`{}` is not a supported ABI for the current target", + abi + ) + .emit(); + } None => { tcx.struct_span_lint_hir(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| { lint.build("use of calling convention not supported on this target").emit() @@ -60,7 +62,7 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab E0781, "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers" ) - .emit() + .emit(); } } diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index b011fb8804d..8ca27b010b6 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -37,7 +37,7 @@ use crate::astconv::AstConv; use crate::check::FnCtxt; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -1307,7 +1307,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { &mut self, fcx: &FnCtxt<'a, 'tcx>, cause: &ObligationCause<'tcx>, - augment_error: &mut dyn FnMut(&mut DiagnosticBuilder<'_>), + augment_error: &mut dyn FnMut(&mut Diagnostic), label_unit_as_expected: bool, ) { self.coerce_inner( @@ -1330,7 +1330,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { cause: &ObligationCause<'tcx>, expression: Option<&'tcx hir::Expr<'tcx>>, mut expression_ty: Ty<'tcx>, - augment_error: Option<&mut dyn FnMut(&mut DiagnosticBuilder<'_>)>, + augment_error: Option<&mut dyn FnMut(&mut Diagnostic)>, label_expression_as_expected: bool, ) { // Incorporate whatever type inference information we have @@ -1520,7 +1520,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fcx: &FnCtxt<'a, 'tcx>, id: hir::HirId, expression: Option<(&'tcx hir::Expr<'tcx>, hir::HirId)>, - ) -> DiagnosticBuilder<'a> { + ) -> DiagnosticBuilder<'a, ErrorReported> { let mut err = fcx.report_mismatched_types(cause, expected, found, ty_err); let mut pointing_at_return_type = false; @@ -1603,7 +1603,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fn add_impl_trait_explanation<'a>( &self, - err: &mut DiagnosticBuilder<'a>, + err: &mut Diagnostic, cause: &ObligationCause<'tcx>, fcx: &FnCtxt<'a, 'tcx>, expected: Ty<'tcx>, diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 466f32aa800..80096b90f95 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -4,7 +4,7 @@ use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::ObligationCause; use rustc_ast::util::parser::PREC_POSTFIX; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_hir::{is_range_literal, Node}; @@ -23,7 +23,7 @@ use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn emit_coerce_suggestions( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expr: &hir::Expr<'tcx>, expr_ty: Ty<'tcx>, expected: Ty<'tcx>, @@ -57,7 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option<DiagnosticBuilder<'tcx>> { + ) -> Option<DiagnosticBuilder<'tcx, ErrorReported>> { self.demand_suptype_with_origin(&self.misc(sp), expected, actual) } @@ -67,7 +67,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option<DiagnosticBuilder<'tcx>> { + ) -> Option<DiagnosticBuilder<'tcx, ErrorReported>> { match self.at(cause, self.param_env).sup(expected, actual) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); @@ -88,7 +88,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option<DiagnosticBuilder<'tcx>> { + ) -> Option<DiagnosticBuilder<'tcx, ErrorReported>> { self.demand_eqtype_with_origin(&self.misc(sp), expected, actual) } @@ -97,7 +97,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option<DiagnosticBuilder<'tcx>> { + ) -> Option<DiagnosticBuilder<'tcx, ErrorReported>> { match self.at(cause, self.param_env).eq(expected, actual) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); @@ -134,7 +134,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, - ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) { + ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorReported>>) { let expected = self.resolve_vars_with_obligations(expected); let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase, None) { @@ -155,7 +155,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn annotate_expected_due_to_let_ty( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expr: &hir::Expr<'_>, error: TypeError<'_>, ) { @@ -251,7 +251,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !lhs.is_syntactic_place_expr() { // We already emitted E0070 "invalid left-hand side of assignment", so we // silence this. - err.delay_as_bug(); + err.downgrade_to_delayed_bug(); } } _ => {} @@ -262,7 +262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// sole field is of the found type, suggest such variants. (Issue #42764) fn suggest_compatible_variants( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expr: &hir::Expr<'_>, expected: Ty<'tcx>, expr_ty: Ty<'tcx>, @@ -899,7 +899,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_for_cast( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, @@ -1039,7 +1039,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id); let suggest_fallible_into_or_lhs_from = - |err: &mut DiagnosticBuilder<'_>, exp_to_found_is_fallible: bool| { + |err: &mut Diagnostic, exp_to_found_is_fallible: bool| { // If we know the expression the expected type is derived from, we might be able // to suggest a widening conversion rather than a narrowing one (which may // panic). For example, given x: u8 and y: u32, if we know the span of "x", @@ -1083,7 +1083,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let suggest_to_change_suffix_or_into = - |err: &mut DiagnosticBuilder<'_>, + |err: &mut Diagnostic, found_to_exp_is_fallible: bool, exp_to_found_is_fallible: bool| { let exp_is_lhs = @@ -1282,11 +1282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Report the type inferred by the return statement. - fn report_closure_inferred_return_type( - &self, - err: &mut DiagnosticBuilder<'_>, - expected: Ty<'tcx>, - ) { + fn report_closure_inferred_return_type(&self, err: &mut Diagnostic, expected: Ty<'tcx>) { if let Some(sp) = self.ret_coercion_span.get() { // If the closure has an explicit return type annotation, or if // the closure's return type has been inferred from outside diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index b08ee414fa7..f84036a7a39 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -25,6 +25,7 @@ use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructEx use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_errors::Diagnostic; use rustc_errors::ErrorReported; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; @@ -60,7 +61,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>, - extend_err: impl Fn(&mut DiagnosticBuilder<'_>), + extend_err: impl Fn(&mut Diagnostic), ) -> Ty<'tcx> { self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected), extend_err) } @@ -69,7 +70,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, - extend_err: impl Fn(&mut DiagnosticBuilder<'_>), + extend_err: impl Fn(&mut Diagnostic), ) -> Ty<'tcx> { let expected_ty = expected.to_option(&self).unwrap_or(self.tcx.types.bool); let mut ty = self.check_expr_with_expectation(expr, expected); @@ -485,7 +486,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map_or(false, |x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_)))) }); if !is_named { - self.tcx.sess.emit_err(AddressOfTemporaryTaken { span: oprnd.span }) + self.tcx.sess.emit_err(AddressOfTemporaryTaken { span: oprnd.span }); } } @@ -1469,14 +1470,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_predicates(obligations) } // FIXME: Need better diagnostics for `FieldMisMatch` error - Err(_) => self - .report_mismatched_types( + Err(_) => { + self.report_mismatched_types( &cause, target_ty, fru_ty, FieldMisMatch(variant.name, ident.name), ) - .emit(), + .emit(); + } } } fru_ty @@ -1484,22 +1486,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect() } _ => { - return self - .report_mismatched_types( - &self.misc(base_expr.span), - adt_ty, - base_ty, - Sorts(ExpectedFound::new(true, adt_ty, base_ty)), - ) - .emit(); + self.report_mismatched_types( + &self.misc(base_expr.span), + adt_ty, + base_ty, + Sorts(ExpectedFound::new(true, adt_ty, base_ty)), + ) + .emit(); + return; } } } _ => { - return self - .tcx + self.tcx .sess .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span }); + return; } } } else { @@ -1528,10 +1530,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .collect(), _ => { - return self - .tcx + self.tcx .sess .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span }); + return; } } }; @@ -1923,7 +1925,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_await_on_field_access( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, field_ident: Ident, base: &'tcx hir::Expr<'tcx>, ty: Ty<'tcx>, @@ -2123,7 +2125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit(); } - fn point_at_param_definition(&self, err: &mut DiagnosticBuilder<'_>, param: ty::ParamTy) { + fn point_at_param_definition(&self, err: &mut Diagnostic, param: ty::ParamTy) { let generics = self.tcx.generics_of(self.body_id.owner.to_def_id()); let generic_param = generics.type_param(¶m, self.tcx); if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param.kind { @@ -2142,7 +2144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_fields_on_recordish( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, def: &'tcx ty::AdtDef, field: Ident, access_span: Span, @@ -2171,7 +2173,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn maybe_suggest_array_indexing( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expr: &hir::Expr<'_>, base: &hir::Expr<'_>, field: Ident, @@ -2195,7 +2197,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_first_deref_field( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expr: &hir::Expr<'_>, base: &hir::Expr<'_>, field: Ident, @@ -2212,7 +2214,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field: Ident, expr_t: Ty<'tcx>, id: HirId, - ) -> DiagnosticBuilder<'_> { + ) -> DiagnosticBuilder<'_, ErrorReported> { let span = field.span; debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index f6cd1369403..0fe5e74da89 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -8,7 +8,7 @@ use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported}; +use rustc_errors::{Applicability, Diagnostic, ErrorReported}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -953,7 +953,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn note_internal_mutation_in_method( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expr: &hir::Expr<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -998,7 +998,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn note_need_for_fn_pointer( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expected: Ty<'tcx>, found: Ty<'tcx>, ) { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index d3d42a1f37c..4b6460b62b7 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -11,7 +11,7 @@ use crate::check::{ use rustc_ast as ast; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticId}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -460,7 +460,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn variadic_error<'tcx>(sess: &Session, span: Span, ty: Ty<'tcx>, cast_ty: &str) { use crate::structured_errors::MissingCastForVariadicArg; - MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit() + MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit(); } for arg in provided_args.iter().skip(expected_arg_count) { @@ -837,7 +837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: hir::ExprKind::Loop(_, _, hir::LoopSource::While, _), .. })) => { - err.delay_as_bug(); + err.downgrade_to_delayed_bug(); } _ => {} } @@ -890,7 +890,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, blk: &'tcx hir::Block<'tcx>, expected_ty: Ty<'tcx>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, ) { if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) { if let StatementAsExpression::NeedsBoxing = boxed { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index f6a2447572f..9e4b88e3746 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -4,7 +4,7 @@ use crate::astconv::AstConv; use rustc_ast::util::parser::ExprPrecedence; use rustc_span::{self, MultiSpan, Span}; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind}; use rustc_hir::lang_items::LangItem; @@ -22,11 +22,7 @@ use rustc_middle::ty::subst::GenericArgKind; use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub(in super::super) fn suggest_semicolon_at_end( - &self, - span: Span, - err: &mut DiagnosticBuilder<'_>, - ) { + pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic) { err.span_suggestion_short( span.shrink_to_hi(), "consider using a semicolon here", @@ -42,7 +38,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// - Possible missing return type if the return type is the default, and not `fn main()`. pub fn suggest_mismatched_types_on_tail( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expr: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -81,7 +77,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// ``` fn suggest_fn_call( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expr: &hir::Expr<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -211,7 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn suggest_deref_ref_or_into( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expr: &hir::Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -312,7 +308,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// in the heap by calling `Box::new()`. pub(in super::super) fn suggest_boxing_when_appropriate( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expr: &hir::Expr<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -347,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// suggest a non-capturing closure pub(in super::super) fn suggest_no_capture_closure( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expected: Ty<'tcx>, found: Ty<'tcx>, ) { @@ -382,7 +378,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self, err))] pub(in super::super) fn suggest_calling_boxed_future_when_appropriate( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expr: &hir::Expr<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -477,7 +473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// it suggests adding a semicolon. fn suggest_missing_semicolon( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expression: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>, ) { @@ -518,7 +514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// type. pub(in super::super) fn suggest_missing_return_type( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, fn_decl: &hir::FnDecl<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -580,7 +576,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// ``` fn try_suggest_return_impl_trait( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expected: Ty<'tcx>, found: Ty<'tcx>, fn_id: hir::HirId, @@ -681,7 +677,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn suggest_missing_break_or_return_expr( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expr: &'tcx hir::Expr<'tcx>, fn_decl: &hir::FnDecl<'_>, expected: Ty<'tcx>, @@ -751,7 +747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn suggest_missing_parentheses( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, expr: &hir::Expr<'_>, ) { let sp = self.tcx.sess.source_map().start_point(expr.span); diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 780a57278c5..999aafbd537 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -14,7 +14,7 @@ pub use self::MethodError::*; use crate::check::FnCtxt; use crate::ObligationCause; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def_id::DefId; @@ -141,7 +141,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self, err, call_expr))] crate fn suggest_method_call( &self, - err: &mut DiagnosticBuilder<'a>, + err: &mut Diagnostic, msg: &str, method_name: Ident, self_ty: Ty<'tcx>, diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 3213148f6a3..ccaea10233d 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -3,7 +3,9 @@ use crate::check::FnCtxt; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{ + pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorReported, +}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; @@ -91,14 +93,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source: SelfSource<'tcx>, error: MethodError<'tcx>, args: Option<&'tcx [hir::Expr<'tcx>]>, - ) -> Option<DiagnosticBuilder<'_>> { + ) -> Option<DiagnosticBuilder<'_, ErrorReported>> { // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { return None; } let report_candidates = |span: Span, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, mut sources: Vec<CandidateSource>, sugg_span: Span| { sources.sort(); @@ -268,7 +270,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (None, true) => "variant", } }; - let mut err = if !actual.references_error() { + // FIXME(eddyb) this intendation is probably unnecessary. + let mut err = { // Suggest clamping down the type if the method that is being attempted to // be used exists at all, and the type is an ambiguous numeric type // ({integer}/{float}). @@ -461,10 +464,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } err } - } else { - tcx.sess.diagnostic().struct_dummy() }; + if actual.references_error() { + err.downgrade_to_delayed_bug(); + } + if let Some(def) = actual.ty_adt_def() { if let Some(full_sp) = tcx.hir().span_if_local(def.did) { let def_sp = tcx.sess.source_map().guess_head_span(full_sp); @@ -625,10 +630,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if self.is_fn_ty(rcvr_ty, span) { - fn report_function<T: std::fmt::Display>( - err: &mut DiagnosticBuilder<'_>, - name: T, - ) { + fn report_function<T: std::fmt::Display>(err: &mut Diagnostic, name: T) { err.note( &format!("`{}` is a function, perhaps you wish to call it", name,), ); @@ -1111,7 +1113,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { crate fn note_unmet_impls_on_type( &self, - err: &mut rustc_errors::DiagnosticBuilder<'_>, + err: &mut Diagnostic, errors: Vec<FulfillmentError<'tcx>>, ) { let all_local_types_needing_impls = @@ -1187,7 +1189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_derive( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, unsatisfied_predicates: &[( ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, @@ -1287,7 +1289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_await_before_method( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, item_name: Ident, ty: Ty<'tcx>, call: &hir::Expr<'_>, @@ -1311,7 +1313,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_use_candidates( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, mut msg: String, candidates: Vec<DefId>, ) { @@ -1416,7 +1418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_valid_traits( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, valid_out_of_scope_traits: Vec<DefId>, ) -> bool { if !valid_out_of_scope_traits.is_empty() { @@ -1454,7 +1456,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_traits_to_import( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, @@ -1983,7 +1985,7 @@ fn find_use_placement<'tcx>(tcx: TyCtxt<'tcx>, target_module: LocalDefId) -> (Op fn print_disambiguation_help<'tcx>( item_name: Ident, args: Option<&'tcx [hir::Expr<'tcx>]>, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, trait_name: String, rcvr_ty: Ty<'_>, kind: ty::AssocKind, diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 6e0b902a00b..e2a91635a2d 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -139,11 +139,13 @@ pub use self::Expectation::*; #[macro_export] macro_rules! type_error_struct { ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({ + let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*); + if $typ.references_error() { - $session.diagnostic().struct_dummy() - } else { - rustc_errors::struct_span_err!($session, $span, $code, $($message)*) + err.downgrade_to_delayed_bug(); } + + err }) } diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index dd49d6f4892..5873b0f52a6 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -3,7 +3,7 @@ use super::method::MethodCallee; use super::{has_expected_num_generic_args, FnCtxt}; use rustc_ast as ast; -use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{self, struct_span_err, Applicability, Diagnostic}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::adjustment::{ @@ -483,7 +483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// suggest calling the function. Returns `true` if suggestion would apply (even if not given). fn add_type_neq_err_label( &self, - err: &mut rustc_errors::DiagnosticBuilder<'_>, + err: &mut Diagnostic, span: Span, ty: Ty<'tcx>, other_ty: Ty<'tcx>, @@ -545,7 +545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_expr: &'tcx hir::Expr<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>, - err: &mut rustc_errors::DiagnosticBuilder<'_>, + err: &mut Diagnostic, is_assign: IsAssign, op: hir::BinOp, ) -> bool { @@ -937,7 +937,7 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool fn suggest_constraining_param( tcx: TyCtxt<'_>, body_id: hir::HirId, - mut err: &mut DiagnosticBuilder<'_>, + mut err: &mut Diagnostic, lhs_ty: Ty<'_>, rhs_ty: Ty<'_>, missing_trait: &str, diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 77ab1d1de42..7c6917734b2 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -2,7 +2,9 @@ use crate::check::FnCtxt; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{ + pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorReported, +}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; @@ -98,7 +100,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { expected: Ty<'tcx>, actual: Ty<'tcx>, ti: TopInfo<'tcx>, - ) -> Option<DiagnosticBuilder<'tcx>> { + ) -> Option<DiagnosticBuilder<'tcx, ErrorReported>> { self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual) } @@ -512,7 +514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } - fn endpoint_has_type(&self, err: &mut DiagnosticBuilder<'_>, span: Span, ty: Ty<'_>) { + fn endpoint_has_type(&self, err: &mut Diagnostic, span: Span, ty: Ty<'_>) { if !ty.references_error() { err.span_label(span, &format!("this is of type `{}`", ty)); } @@ -645,7 +647,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn borrow_pat_suggestion( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diagnostic, pat: &Pat<'_>, inner: &Pat<'_>, expected: Ty<'tcx>, @@ -783,7 +785,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn maybe_suggest_range_literal( &self, - e: &mut DiagnosticBuilder<'_>, + e: &mut Diagnostic, opt_def_id: Option<hir::def_id::DefId>, ident: Ident, ) -> bool { @@ -817,7 +819,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn emit_bad_pat_path<'b>( &self, - mut e: DiagnosticBuilder<'_>, + mut e: DiagnosticBuilder<'_, ErrorReported>, pat_span: Span, res: Res, pat_res: Res, @@ -1368,7 +1370,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant: &VariantDef, pat: &'_ Pat<'_>, fields: &[hir::PatField<'_>], - ) -> Option<DiagnosticBuilder<'_>> { + ) -> Option<DiagnosticBuilder<'_, ErrorReported>> { // if this is a tuple struct, then all field names will be numbers // so if any fields in a struct pattern use shorthand syntax, they will // be invalid identifiers (for example, Foo { 0, 1 }). @@ -1441,7 +1443,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inexistent_fields: &[Ident], unmentioned_fields: &mut Vec<(&ty::FieldDef, Ident)>, variant: &ty::VariantDef, - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let tcx = self.tcx; let (field_names, t, plural) = if inexistent_fields.len() == 1 { (format!("a field named `{}`", inexistent_fields[0]), "this", "") @@ -1537,7 +1539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &Pat<'_>, fields: &'tcx [hir::PatField<'tcx>], variant: &ty::VariantDef, - ) -> Option<DiagnosticBuilder<'tcx>> { + ) -> Option<DiagnosticBuilder<'tcx, ErrorReported>> { if let (CtorKind::Fn, PatKind::Struct(qpath, ..)) = (variant.ctor_kind, &pat.kind) { let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { s.print_qpath(qpath, false) @@ -1619,7 +1621,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat: &Pat<'_>, fields: &'tcx [hir::PatField<'tcx>], - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let mut err = self .tcx .sess @@ -1711,7 +1713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unmentioned_fields: &[(&ty::FieldDef, Ident)], have_inaccessible_fields: bool, fields: &'tcx [hir::PatField<'tcx>], - ) -> DiagnosticBuilder<'tcx> { + ) -> DiagnosticBuilder<'tcx, ErrorReported> { let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" }; let field_names = if unmentioned_fields.len() == 1 { format!("field `{}`{}", unmentioned_fields[0].1, inaccessible) diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 55757251e26..4ab654560ea 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -4,7 +4,7 @@ use crate::constrained_generic_params::{identify_constrained_generic_params, Par use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit as hir_visit; @@ -448,7 +448,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe for more information", ); - err.emit() + err.emit(); } } } @@ -843,7 +843,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { "using {} as const generic parameters is forbidden", unsupported_type ), - ) + ); } else { let mut err = tcx.sess.struct_span_err( hir_ty.span, @@ -858,7 +858,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { "more complex types are supported with `#![feature(adt_const_params)]`", ); } - err.emit() + err.emit(); } }; @@ -1729,12 +1729,14 @@ fn check_variances_for_type_defn<'tcx>( match param.name { hir::ParamName::Error => {} - _ => report_bivariance(tcx, param), + _ => { + report_bivariance(tcx, param); + } } } } -fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) { +fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) -> ErrorReported { let span = param.span; let param_name = param.name.ident().name; let mut err = error_392(tcx, span, param_name); @@ -1943,7 +1945,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -fn error_392(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) -> DiagnosticBuilder<'_> { +fn error_392( + tcx: TyCtxt<'_>, + span: Span, + param_name: Symbol, +) -> DiagnosticBuilder<'_, ErrorReported> { let mut err = struct_span_err!(tcx.sess, span, E0392, "parameter `{}` is never used", param_name); err.span_label(span, "unused parameter"); diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs index 401ba188728..ac1f2db848f 100644 --- a/compiler/rustc_typeck/src/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -74,7 +74,8 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type); - match can_type_implement_copy(tcx, param_env, self_type) { + let cause = traits::ObligationCause::misc(span, impl_hir_id); + match can_type_implement_copy(tcx, param_env, self_type, cause) { Ok(()) => {} Err(CopyImplementationError::InfrigingFields(fields)) => { let item = tcx.hir().expect_item(impl_did); @@ -93,7 +94,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { for span in fields.iter().map(|f| tcx.def_span(f.did)) { err.span_label(span, "this field does not implement `Copy`"); } - err.emit() + err.emit(); } Err(CopyImplementationError::NotAnAdt) => { let item = tcx.hir().expect_item(impl_did); diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index 54fffeb3cda..6c9059cfdd4 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -159,7 +159,7 @@ fn emit_orphan_check_error<'tcx>( generics: &hir::Generics<'tcx>, err: traits::OrphanCheckErr<'tcx>, ) -> Result<!, ErrorReported> { - match err { + Err(match err { traits::OrphanCheckErr::NonLocalInputType(tys) => { let mut err = struct_span_err!( tcx.sess, @@ -269,9 +269,7 @@ fn emit_orphan_check_error<'tcx>( .emit(), } } - } - - Err(ErrorReported) + }) } #[derive(Default)] @@ -439,6 +437,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: } match t.kind() { + ty::Adt(def, substs) if def.is_phantom_data() => substs.super_visit_with(self), ty::Adt(def, substs) => { // @lcnr: This is the only place where cycles can happen. We avoid this // by only visiting each `DefId` once. diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 392144ca763..cf2164763b1 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -26,7 +26,7 @@ use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_errors::{struct_span_err, Applicability}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; @@ -321,7 +321,7 @@ fn bad_placeholder<'tcx>( tcx: TyCtxt<'tcx>, mut spans: Vec<Span>, kind: &'static str, -) -> rustc_errors::DiagnosticBuilder<'tcx> { +) -> DiagnosticBuilder<'tcx, ErrorReported> { let kind = if kind.ends_with('s') { format!("{}es", kind) } else { format!("{}s", kind) }; spans.sort(); @@ -730,7 +730,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { // These don't define types. hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) - | hir::ItemKind::Macro(_) + | hir::ItemKind::Macro(..) | hir::ItemKind::Mod(_) | hir::ItemKind::GlobalAsm(_) => {} hir::ItemKind::ForeignMod { items, .. } => { @@ -1277,19 +1277,21 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { return None; } - Some(item) => tcx - .sess - .struct_span_err(item.span, "Not a function") - .span_note(attr_span, "required by this annotation") - .note( - "All `#[rustc_must_implement_one_of]` arguments \ + Some(item) => { + tcx.sess + .struct_span_err(item.span, "Not a function") + .span_note(attr_span, "required by this annotation") + .note( + "All `#[rustc_must_implement_one_of]` arguments \ must be associated function names", - ) - .emit(), - None => tcx - .sess - .struct_span_err(ident.span, "Function not found in this trait") - .emit(), + ) + .emit(); + } + None => { + tcx.sess + .struct_span_err(ident.span, "Function not found in this trait") + .emit(); + } } Some(()) diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 78097e3697f..6cef3e9d940 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -393,13 +393,14 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc tcx.def_path_str(trait_ref.def_id), ), ) - .emit() + .emit(); } } - _ => tcx - .sess - .struct_span_err(span, &format!("cannot specialize on `{:?}`", predicate)) - .emit(), + _ => { + tcx.sess + .struct_span_err(span, &format!("cannot specialize on `{:?}`", predicate)) + .emit(); + } } } diff --git a/compiler/rustc_typeck/src/structured_errors.rs b/compiler/rustc_typeck/src/structured_errors.rs index 04d04304e70..8621375fc63 100644 --- a/compiler/rustc_typeck/src/structured_errors.rs +++ b/compiler/rustc_typeck/src/structured_errors.rs @@ -6,7 +6,7 @@ pub use self::{ missing_cast_for_variadic_arg::*, sized_unsized_cast::*, wrong_number_of_generic_args::*, }; -use rustc_errors::{DiagnosticBuilder, DiagnosticId}; +use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorReported}; use rustc_session::Session; pub trait StructuredDiagnostic<'tcx> { @@ -14,7 +14,7 @@ pub trait StructuredDiagnostic<'tcx> { fn code(&self) -> DiagnosticId; - fn diagnostic(&self) -> DiagnosticBuilder<'tcx> { + fn diagnostic(&self) -> DiagnosticBuilder<'tcx, ErrorReported> { let err = self.diagnostic_common(); if self.session().teach(&self.code()) { @@ -24,13 +24,19 @@ pub trait StructuredDiagnostic<'tcx> { } } - fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx>; + fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorReported>; - fn diagnostic_regular(&self, err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> { + fn diagnostic_regular( + &self, + err: DiagnosticBuilder<'tcx, ErrorReported>, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { err } - fn diagnostic_extended(&self, err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> { + fn diagnostic_extended( + &self, + err: DiagnosticBuilder<'tcx, ErrorReported>, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { err } } diff --git a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs index 674b0e463f5..2dc9f26004c 100644 --- a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs +++ b/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs @@ -1,5 +1,5 @@ use crate::structured_errors::StructuredDiagnostic; -use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorReported}; use rustc_middle::ty::{Ty, TypeFoldable}; use rustc_session::Session; use rustc_span::Span; @@ -20,16 +20,16 @@ impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx> { rustc_errors::error_code!(E0617) } - fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> { - let mut err = if self.ty.references_error() { - self.sess.diagnostic().struct_dummy() - } else { - self.sess.struct_span_fatal_with_code( - self.span, - &format!("can't pass `{}` to variadic function", self.ty), - self.code(), - ) - }; + fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorReported> { + let mut err = self.sess.struct_span_fatal_with_code( + self.span, + &format!("can't pass `{}` to variadic function", self.ty), + self.code(), + ); + + if self.ty.references_error() { + err.downgrade_to_delayed_bug(); + } if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.span) { err.span_suggestion( @@ -45,7 +45,10 @@ impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx> { err } - fn diagnostic_extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> { + fn diagnostic_extended( + &self, + mut err: DiagnosticBuilder<'tcx, ErrorReported>, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { err.note(&format!( "certain types, like `{}`, must be casted before passing them to a \ variadic function, because of arcane ABI rules dictated by the C \ diff --git a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs index d0477a3e748..8d2cdbb170b 100644 --- a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs +++ b/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs @@ -1,5 +1,5 @@ use crate::structured_errors::StructuredDiagnostic; -use rustc_errors::{DiagnosticBuilder, DiagnosticId}; +use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorReported}; use rustc_middle::ty::{Ty, TypeFoldable}; use rustc_session::Session; use rustc_span::Span; @@ -20,22 +20,27 @@ impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCast<'tcx> { rustc_errors::error_code!(E0607) } - fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> { + fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorReported> { + let mut err = self.sess.struct_span_fatal_with_code( + self.span, + &format!( + "cannot cast thin pointer `{}` to fat pointer `{}`", + self.expr_ty, self.cast_ty + ), + self.code(), + ); + if self.expr_ty.references_error() { - self.sess.diagnostic().struct_dummy() - } else { - self.sess.struct_span_fatal_with_code( - self.span, - &format!( - "cannot cast thin pointer `{}` to fat pointer `{}`", - self.expr_ty, self.cast_ty - ), - self.code(), - ) + err.downgrade_to_delayed_bug(); } + + err } - fn diagnostic_extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> { + fn diagnostic_extended( + &self, + mut err: DiagnosticBuilder<'tcx, ErrorReported>, + ) -> DiagnosticBuilder<'tcx, ErrorReported> { err.help( "Thin pointers are \"simple\" pointers: they are purely a reference to a memory address. diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index a1c29457709..b763b51dd01 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -1,5 +1,7 @@ use crate::structured_errors::StructuredDiagnostic; -use rustc_errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_errors::{ + pluralize, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorReported, +}; use rustc_hir as hir; use rustc_middle::hir::map::fn_sig; use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath; @@ -362,7 +364,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn start_diagnostics(&self) -> DiagnosticBuilder<'tcx> { + fn start_diagnostics(&self) -> DiagnosticBuilder<'tcx, ErrorReported> { let span = self.path_segment.ident.span; let msg = self.create_error_message(); @@ -370,7 +372,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } /// Builds the `expected 1 type argument / supplied 2 type arguments` message. - fn notify(&self, err: &mut DiagnosticBuilder<'_>) { + fn notify(&self, err: &mut Diagnostic) { let (quantifier, bound) = self.get_quantifier_and_bound(); let provided_args = self.num_provided_args(); @@ -422,7 +424,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest(&self, err: &mut DiagnosticBuilder<'_>) { + fn suggest(&self, err: &mut Diagnostic) { debug!( "suggest(self.provided {:?}, self.gen_args.span(): {:?})", self.num_provided_args(), @@ -449,7 +451,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// ```text /// type Map = HashMap<String>; /// ``` - fn suggest_adding_args(&self, err: &mut DiagnosticBuilder<'_>) { + fn suggest_adding_args(&self, err: &mut Diagnostic) { if self.gen_args.parenthesized { return; } @@ -465,7 +467,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest_adding_lifetime_args(&self, err: &mut DiagnosticBuilder<'_>) { + fn suggest_adding_lifetime_args(&self, err: &mut Diagnostic) { debug!("suggest_adding_lifetime_args(path_segment: {:?})", self.path_segment); let num_missing_args = self.num_missing_lifetime_args(); let num_params_to_take = num_missing_args; @@ -547,7 +549,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest_adding_type_and_const_args(&self, err: &mut DiagnosticBuilder<'_>) { + fn suggest_adding_type_and_const_args(&self, err: &mut Diagnostic) { let num_missing_args = self.num_missing_type_or_const_args(); let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args)); @@ -602,7 +604,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// ```text /// type Map = HashMap<String, String, String, String>; /// ``` - fn suggest_removing_args_or_generics(&self, err: &mut DiagnosticBuilder<'_>) { + fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) { let num_provided_lt_args = self.num_provided_lifetime_args(); let num_provided_type_const_args = self.num_provided_type_or_const_args(); let num_provided_args = num_provided_lt_args + num_provided_type_const_args; @@ -617,7 +619,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let remove_entire_generics = num_redundant_args >= self.gen_args.args.len(); - let remove_lifetime_args = |err: &mut DiagnosticBuilder<'_>| { + let remove_lifetime_args = |err: &mut Diagnostic| { let mut lt_arg_spans = Vec::new(); let mut found_redundant = false; for arg in self.gen_args.args { @@ -659,7 +661,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { ); }; - let remove_type_or_const_args = |err: &mut DiagnosticBuilder<'_>| { + let remove_type_or_const_args = |err: &mut Diagnostic| { let mut gen_arg_spans = Vec::new(); let mut found_redundant = false; for arg in self.gen_args.args { @@ -729,7 +731,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } /// Builds the `type defined here` message. - fn show_definition(&self, err: &mut DiagnosticBuilder<'_>) { + fn show_definition(&self, err: &mut Diagnostic) { let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) { if self.tcx.sess.source_map().span_to_snippet(def_span).is_ok() { def_span.into() @@ -789,7 +791,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for WrongNumberOfGenericArgs<'_, 'tcx> { rustc_errors::error_code!(E0107) } - fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> { + fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorReported> { let mut err = self.start_diagnostics(); self.notify(&mut err); diff --git a/library/core/benches/slice.rs b/library/core/benches/slice.rs index 04efa520787..9b86a0ca97c 100644 --- a/library/core/benches/slice.rs +++ b/library/core/benches/slice.rs @@ -89,6 +89,15 @@ fn binary_search_l3_worst_case(b: &mut Bencher) { binary_search_worst_case(b, Cache::L3); } +#[derive(Clone)] +struct Rgb(u8, u8, u8); + +impl Rgb { + fn gen(i: usize) -> Self { + Rgb(i as u8, (i as u8).wrapping_add(7), (i as u8).wrapping_add(42)) + } +} + macro_rules! rotate { ($fn:ident, $n:expr, $mapper:expr) => { #[bench] @@ -104,17 +113,43 @@ macro_rules! rotate { }; } -#[derive(Clone)] -struct Rgb(u8, u8, u8); - rotate!(rotate_u8, 32, |i| i as u8); -rotate!(rotate_rgb, 32, |i| Rgb(i as u8, (i as u8).wrapping_add(7), (i as u8).wrapping_add(42))); +rotate!(rotate_rgb, 32, Rgb::gen); rotate!(rotate_usize, 32, |i| i); rotate!(rotate_16_usize_4, 16, |i| [i; 4]); rotate!(rotate_16_usize_5, 16, |i| [i; 5]); rotate!(rotate_64_usize_4, 64, |i| [i; 4]); rotate!(rotate_64_usize_5, 64, |i| [i; 5]); +macro_rules! swap_with_slice { + ($fn:ident, $n:expr, $mapper:expr) => { + #[bench] + fn $fn(b: &mut Bencher) { + let mut x = (0usize..$n).map(&$mapper).collect::<Vec<_>>(); + let mut y = ($n..($n * 2)).map(&$mapper).collect::<Vec<_>>(); + let mut skip = 0; + b.iter(|| { + for _ in 0..32 { + x[skip..].swap_with_slice(&mut y[..($n - skip)]); + skip = black_box(skip + 1) % 8; + } + black_box((x[$n / 3].clone(), y[$n * 2 / 3].clone())) + }) + } + }; +} + +swap_with_slice!(swap_with_slice_u8_30, 30, |i| i as u8); +swap_with_slice!(swap_with_slice_u8_3000, 3000, |i| i as u8); +swap_with_slice!(swap_with_slice_rgb_30, 30, Rgb::gen); +swap_with_slice!(swap_with_slice_rgb_3000, 3000, Rgb::gen); +swap_with_slice!(swap_with_slice_usize_30, 30, |i| i); +swap_with_slice!(swap_with_slice_usize_3000, 3000, |i| i); +swap_with_slice!(swap_with_slice_4x_usize_30, 30, |i| [i; 4]); +swap_with_slice!(swap_with_slice_4x_usize_3000, 3000, |i| [i; 4]); +swap_with_slice!(swap_with_slice_5x_usize_30, 30, |i| [i; 5]); +swap_with_slice!(swap_with_slice_5x_usize_3000, 3000, |i| [i; 5]); + #[bench] fn fill_byte_sized(b: &mut Bencher) { #[derive(Copy, Clone)] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 989ec0639cd..b5c1ae37e5e 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -700,10 +700,49 @@ pub unsafe fn uninitialized<T>() -> T { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] pub const fn swap<T>(x: &mut T, y: &mut T) { - // SAFETY: the raw pointers have been created from safe mutable references satisfying all the - // constraints on `ptr::swap_nonoverlapping_one` + // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary + // reinterpretation of values as (chunkable) byte arrays, and the loop in the + // block optimization in `swap_slice` is hard to rewrite back + // into the (unoptimized) direct swapping implementation, so we disable it. + // FIXME(eddyb) the block optimization also prevents MIR optimizations from + // understanding `mem::replace`, `Option::take`, etc. - a better overall + // solution might be to make `ptr::swap_nonoverlapping` into an intrinsic, which + // a backend can choose to implement using the block optimization, or not. + #[cfg(not(target_arch = "spirv"))] + { + // For types that are larger multiples of their alignment, the simple way + // tends to copy the whole thing to stack rather than doing it one part + // at a time, so instead treat them as one-element slices and piggy-back + // the slice optimizations that will split up the swaps. + if size_of::<T>() / align_of::<T>() > 4 { + // SAFETY: exclusive references always point to one non-overlapping + // element and are non-null and properly aligned. + return unsafe { ptr::swap_nonoverlapping(x, y, 1) }; + } + } + + // If a scalar consists of just a small number of alignment units, let + // the codegen just swap those pieces directly, as it's likely just a + // few instructions and anything else is probably overcomplicated. + // + // Most importantly, this covers primitives and simd types that tend to + // have size=align where doing anything else can be a pessimization. + // (This will also be used for ZSTs, though any solution works for them.) + swap_simple(x, y); +} + +/// Same as [`swap`] semantically, but always uses the simple implementation. +/// +/// Used elsewhere in `mem` and `ptr` at the bottom layer of calls. +#[rustc_const_unstable(feature = "const_swap", issue = "83163")] +#[inline] +pub(crate) const fn swap_simple<T>(x: &mut T, y: &mut T) { + // SAFETY: exclusive references are always valid to read/write, + // are non-overlapping, and nothing here panics so it's drop-safe. unsafe { - ptr::swap_nonoverlapping_one(x, y); + let z = ptr::read(x); + ptr::copy_nonoverlapping(y, x, 1); + ptr::write(y, z); } } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 8ab72e6aeea..ff71fadb614 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -419,106 +419,58 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) { #[stable(feature = "swap_nonoverlapping", since = "1.27.0")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { - let x = x as *mut u8; - let y = y as *mut u8; - let len = mem::size_of::<T>() * count; - // SAFETY: the caller must guarantee that `x` and `y` are - // valid for writes and properly aligned. - unsafe { swap_nonoverlapping_bytes(x, y, len) } -} + macro_rules! attempt_swap_as_chunks { + ($ChunkTy:ty) => { + if mem::align_of::<T>() >= mem::align_of::<$ChunkTy>() + && mem::size_of::<T>() % mem::size_of::<$ChunkTy>() == 0 + { + let x: *mut MaybeUninit<$ChunkTy> = x.cast(); + let y: *mut MaybeUninit<$ChunkTy> = y.cast(); + let count = count * (mem::size_of::<T>() / mem::size_of::<$ChunkTy>()); + // SAFETY: these are the same bytes that the caller promised were + // ok, just typed as `MaybeUninit<ChunkTy>`s instead of as `T`s. + // The `if` condition above ensures that we're not violating + // alignment requirements, and that the division is exact so + // that we don't lose any bytes off the end. + return unsafe { swap_nonoverlapping_simple(x, y, count) }; + } + }; + } -#[inline] -#[rustc_const_unstable(feature = "const_swap", issue = "83163")] -pub(crate) const unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) { - // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary - // reinterpretation of values as (chunkable) byte arrays, and the loop in the - // block optimization in `swap_nonoverlapping_bytes` is hard to rewrite back - // into the (unoptimized) direct swapping implementation, so we disable it. - // FIXME(eddyb) the block optimization also prevents MIR optimizations from - // understanding `mem::replace`, `Option::take`, etc. - a better overall - // solution might be to make `swap_nonoverlapping` into an intrinsic, which - // a backend can choose to implement using the block optimization, or not. - #[cfg(not(target_arch = "spirv"))] + // Split up the slice into small power-of-two-sized chunks that LLVM is able + // to vectorize (unless it's a special type with more-than-pointer alignment, + // because we don't want to pessimize things like slices of SIMD vectors.) + if mem::align_of::<T>() <= mem::size_of::<usize>() + && (!mem::size_of::<T>().is_power_of_two() + || mem::size_of::<T>() > mem::size_of::<usize>() * 2) { - // Only apply the block optimization in `swap_nonoverlapping_bytes` for types - // at least as large as the block size, to avoid pessimizing codegen. - if mem::size_of::<T>() >= 32 { - // SAFETY: the caller must uphold the safety contract for `swap_nonoverlapping`. - unsafe { swap_nonoverlapping(x, y, 1) }; - return; - } + attempt_swap_as_chunks!(usize); + attempt_swap_as_chunks!(u8); } - // Direct swapping, for the cases not going through the block optimization. - // SAFETY: the caller must guarantee that `x` and `y` are valid - // for writes, properly aligned, and non-overlapping. - unsafe { - let z = read(x); - copy_nonoverlapping(y, x, 1); - write(y, z); - } + // SAFETY: Same preconditions as this function + unsafe { swap_nonoverlapping_simple(x, y, count) } } +/// Same behaviour and safety conditions as [`swap_nonoverlapping`] +/// +/// LLVM can vectorize this (at least it can for the power-of-two-sized types +/// `swap_nonoverlapping` tries to use) so no need to manually SIMD it. #[inline] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] -const unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { - // The approach here is to utilize simd to swap x & y efficiently. Testing reveals - // that swapping either 32 bytes or 64 bytes at a time is most efficient for Intel - // Haswell E processors. LLVM is more able to optimize if we give a struct a - // #[repr(simd)], even if we don't actually use this struct directly. - // - // FIXME repr(simd) broken on emscripten and redox - #[cfg_attr(not(any(target_os = "emscripten", target_os = "redox")), repr(simd))] - struct Block(u64, u64, u64, u64); - struct UnalignedBlock(u64, u64, u64, u64); - - let block_size = mem::size_of::<Block>(); - - // Loop through x & y, copying them `Block` at a time - // The optimizer should unroll the loop fully for most types - // N.B. We can't use a for loop as the `range` impl calls `mem::swap` recursively +const unsafe fn swap_nonoverlapping_simple<T>(x: *mut T, y: *mut T, count: usize) { let mut i = 0; - while i + block_size <= len { - // Create some uninitialized memory as scratch space - // Declaring `t` here avoids aligning the stack when this loop is unused - let mut t = mem::MaybeUninit::<Block>::uninit(); - let t = t.as_mut_ptr() as *mut u8; - - // SAFETY: As `i < len`, and as the caller must guarantee that `x` and `y` are valid - // for `len` bytes, `x + i` and `y + i` must be valid addresses, which fulfills the - // safety contract for `add`. - // - // Also, the caller must guarantee that `x` and `y` are valid for writes, properly aligned, - // and non-overlapping, which fulfills the safety contract for `copy_nonoverlapping`. - unsafe { - let x = x.add(i); - let y = y.add(i); + while i < count { + let x: &mut T = + // SAFETY: By precondition, `i` is in-bounds because it's below `n` + unsafe { &mut *x.add(i) }; + let y: &mut T = + // SAFETY: By precondition, `i` is in-bounds because it's below `n` + // and it's distinct from `x` since the ranges are non-overlapping + unsafe { &mut *y.add(i) }; + mem::swap_simple(x, y); - // Swap a block of bytes of x & y, using t as a temporary buffer - // This should be optimized into efficient SIMD operations where available - copy_nonoverlapping(x, t, block_size); - copy_nonoverlapping(y, x, block_size); - copy_nonoverlapping(t, y, block_size); - } - i += block_size; - } - - if i < len { - // Swap any remaining bytes - let mut t = mem::MaybeUninit::<UnalignedBlock>::uninit(); - let rem = len - i; - - let t = t.as_mut_ptr() as *mut u8; - - // SAFETY: see previous safety comment. - unsafe { - let x = x.add(i); - let y = y.add(i); - - copy_nonoverlapping(x, t, rem); - copy_nonoverlapping(y, x, rem); - copy_nonoverlapping(t, y, rem); - } + i += 1; } } diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md new file mode 100644 index 00000000000..d7345ad0c33 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md @@ -0,0 +1,221 @@ +# `check-cfg` + +The tracking issue for this feature is: [#82450](https://github.com/rust-lang/rust/issues/82450). + +------------------------ + +This feature allows you to enable complete or partial checking of configuration. + +`rustc` accepts the `--check-cfg` option, which specifies whether to check conditions and how to +check them. The `--check-cfg` option takes a value, called the _check cfg specification_. The +check cfg specification is parsed using the Rust metadata syntax, just as the `--cfg` option is. + +`--check-cfg` option can take one of two forms: + +1. `--check-cfg names(...)` enables checking condition names. +2. `--check-cfg values(...)` enables checking the values within list-valued conditions. + +These two options are independent. `names` checks only the namespace of condition names +while `values` checks only the namespace of the values of list-valued conditions. + +## The `names(...)` form + +The `names(...)` form enables checking the names. This form uses a named list: + +```bash +rustc --check-cfg 'names(name1, name2, ... nameN)' +``` + +where each `name` is a bare identifier (has no quotes). The order of the names is not significant. + +If `--check-cfg names(...)` is specified at least once, then `rustc` will check all references to +condition names. `rustc` will check every `#[cfg]` attribute, `#[cfg_attr]` attribute, `cfg` clause +inside `#[link]` attribute and `cfg!(...)` call against the provided list of expected condition +names. If a name is not present in this list, then `rustc` will report an `unexpected_cfgs` lint +diagnostic. The default diagnostic level for this lint is `Warn`. + +If `--check-cfg names(...)` is not specified, then `rustc` will not check references to condition +names. + +`--check-cfg names(...)` may be specified more than once. The result is that the list of valid +condition names is merged across all options. It is legal for a condition name to be specified +more than once; redundantly specifying a condition name has no effect. + +To enable checking condition names with an empty set of valid condition names, use the following +form. The parentheses are required. + +```bash +rustc --check-cfg 'names()' +``` + +Note that `--check-cfg 'names()'` is _not_ equivalent to omitting the option entirely. +The first form enables checking condition names, while specifying that there are no valid +condition names (outside of the set of well-known names defined by `rustc`). Omitting the +`--check-cfg 'names(...)'` option does not enable checking condition names. + +Conditions that are enabled are implicitly valid; it is unnecessary (but legal) to specify a +condition name as both enabled and valid. For example, the following invocations are equivalent: + +```bash +# condition names will be checked, and 'has_time_travel' is valid +rustc --cfg 'has_time_travel' --check-cfg 'names()' + +# condition names will be checked, and 'has_time_travel' is valid +rustc --cfg 'has_time_travel' --check-cfg 'names(has_time_travel)' +``` + +In contrast, the following two invocations are _not_ equivalent: + +```bash +# condition names will not be checked (because there is no --check-cfg names(...)) +rustc --cfg 'has_time_travel' + +# condition names will be checked, and 'has_time_travel' is both valid and enabled. +rustc --cfg 'has_time_travel' --check-cfg 'names(has_time_travel)' +``` + +## The `values(...)` form + +The `values(...)` form enables checking the values within list-valued conditions. It has this +form: + +```bash +rustc --check-cfg `values(name, "value1", "value2", ... "valueN")' +``` + +where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal +string. `name` specifies the name of the condition, such as `feature` or `target_os`. + +When the `values(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]` +attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]` +and `cfg!(name = "value")` call. It will check that the `"value"` specified is present in the +list of expected values. If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs` +lint diagnostic. The default diagnostic level for this lint is `Warn`. + +The form `values()` is an error, because it does not specify a condition name. + +To enable checking of values, but to provide an empty set of valid values, use this form: + +```bash +rustc --check-cfg `values(name)` +``` + +The `--check-cfg values(...)` option can be repeated, both for the same condition name and for +different names. If it is repeated for the same condition name, then the sets of values for that +condition are merged together. + +## Examples + +Consider this command line: + +```bash +rustc --check-cfg 'names(feature)' \ + --check-cfg 'values(feature,"lion","zebra")' \ + --cfg 'feature="lion"' -Z unstable-options \ + example.rs +``` + +This command line indicates that this crate has two features: `lion` and `zebra`. The `lion` +feature is enabled, while the `zebra` feature is disabled. Consider compiling this code: + +```rust +// This is expected, and tame_lion() will be compiled +#[cfg(feature = "lion")] +fn tame_lion(lion: Lion) {} + +// This is expected, and ride_zebra() will NOT be compiled. +#[cfg(feature = "zebra")] +fn ride_zebra(zebra: Zebra) {} + +// This is UNEXPECTED, and will cause a compiler warning (by default). +#[cfg(feature = "platypus")] +fn poke_platypus() {} + +// This is UNEXPECTED, because 'feechure' is not a known condition name, +// and will cause a compiler warning (by default). +#[cfg(feechure = "lion")] +fn tame_lion() {} +``` + +> Note: The `--check-cfg names(feature)` option is necessary only to enable checking the condition +> name, as in the last example. `feature` is a well-known (always-expected) condition name, and so +> it is not necessary to specify it in a `--check-cfg 'names(...)'` option. That option can be +> shortened to > `--check-cfg names()` in order to enable checking well-known condition names. + +### Example: Checking condition names, but not values + +```bash +# This turns on checking for condition names, but not values, such as 'feature' values. +rustc --check-cfg 'names(is_embedded, has_feathers)' \ + --cfg has_feathers --cfg 'feature = "zapping"' -Z unstable-options +``` + +```rust +#[cfg(is_embedded)] // This is expected as "is_embedded" was provided in names() +fn do_embedded() {} + +#[cfg(has_feathers)] // This is expected as "has_feathers" was provided in names() +fn do_features() {} + +#[cfg(has_mumble_frotz)] // This is UNEXPECTED because names checking is enable and + // "has_mumble_frotz" was not provided in names() +fn do_mumble_frotz() {} + +#[cfg(feature = "lasers")] // This doesn't raise a warning, because values checking for "feature" + // was never used +fn shoot_lasers() {} +``` + +### Example: Checking feature values, but not condition names + +```bash +# This turns on checking for feature values, but not for condition names. +rustc --check-cfg 'values(feature, "zapping", "lasers")' \ + --cfg 'feature="zapping"' -Z unstable-options +``` + +```rust +#[cfg(is_embedded)] // This is doesn't raise a warning, because names checking was not + // enable (ie not names()) +fn do_embedded() {} + +#[cfg(has_feathers)] // Same as above, --check-cfg names(...) was never used so no name + // checking is performed +fn do_features() {} + + +#[cfg(feature = "lasers")] // This is expected, "lasers" is in the values(feature) list +fn shoot_lasers() {} + +#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in the + // --check-cfg values(feature) list +fn write_shakespeare() {} +``` + +### Example: Checking both condition names and feature values + +```bash +# This turns on checking for feature values and for condition names. +rustc --check-cfg 'names(is_embedded, has_feathers)' \ + --check-cfg 'values(feature, "zapping", "lasers")' \ + --cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options +``` + +```rust +#[cfg(is_embedded)] // This is expected because "is_embedded" was provided in names() +fn do_embedded() {} + +#[cfg(has_feathers)] // This is expected because "has_feathers" was provided in names() +fn do_features() {} + +#[cfg(has_mumble_frotz)] // This is UNEXPECTED, because has_mumble_frotz is not in the + // --check-cfg names(...) list +fn do_mumble_frotz() {} + +#[cfg(feature = "lasers")] // This is expected, "lasers" is in the values(feature) list +fn shoot_lasers() {} + +#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in + // the values(feature) list +fn write_shakespear() {} +``` diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 76994f2ee17..1e0c1e8f1f3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1855,7 +1855,7 @@ fn clean_maybe_renamed_item( ItemKind::Fn(ref sig, ref generics, body_id) => { clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) } - ItemKind::Macro(ref macro_def) => { + ItemKind::Macro(ref macro_def, _) => { let ty_vis = cx.tcx.visibility(def_id).clean(cx); MacroItem(Macro { source: display_macro_source(cx, name, macro_def, def_id, ty_vis), diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index dff370ab750..58ca8869ea9 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -69,9 +69,7 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String match rustc_parse::maybe_new_parser_from_source_str(&sess, file_name, snippet.clone()) { Ok(parser) => parser, Err(diagnostics) => { - for mut diagnostic in diagnostics { - diagnostic.cancel(); - } + drop(diagnostics); return None; } }; @@ -79,7 +77,7 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String // Reparse a single token tree. let mut reparsed_trees = match parser.parse_all_token_trees() { Ok(reparsed_trees) => reparsed_trees, - Err(mut diagnostic) => { + Err(diagnostic) => { diagnostic.cancel(); return None; } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 696397c5f67..a08732be1c5 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -551,10 +551,7 @@ crate fn make_test( let mut parser = match maybe_new_parser_from_source_str(&sess, filename, source) { Ok(p) => p, Err(errs) => { - for mut err in errs { - err.cancel(); - } - + drop(errs); return (found_main, found_extern_crate, found_macro); } }; @@ -594,7 +591,7 @@ crate fn make_test( } } Ok(None) => break, - Err(mut e) => { + Err(e) => { e.cancel(); break; } @@ -1164,7 +1161,7 @@ impl<'a, 'hir, 'tcx> intravisit::Visitor<'hir> for HirCollector<'a, 'hir, 'tcx> fn visit_item(&mut self, item: &'hir hir::Item<'_>) { let name = match &item.kind { - hir::ItemKind::Macro(ref macro_def) => { + hir::ItemKind::Macro(ref macro_def, _) => { // FIXME(#88038): Non exported macros have historically not been tested, // but we really ought to start testing them. let def_id = item.def_id.to_def_id(); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 7eff725989c..9d3e58a3a66 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -720,12 +720,10 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( let mut msg = tcx.sess.struct_err(&format!("couldn't generate documentation: {}", e.error)); let file = e.file.display().to_string(); - if file.is_empty() { - msg.emit() - } else { - msg.note(&format!("failed to create or modify \"{}\"", file)).emit() + if !file.is_empty() { + msg.note(&format!("failed to create or modify \"{}\"", file)); } - Err(ErrorReported) + Err(msg.emit()) } } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 33a1530d588..3ebd28e83b1 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -3,7 +3,7 @@ //! [RFC 1946]: https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet}; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::def::{ DefKind, Namespace::{self, *}, @@ -1434,7 +1434,7 @@ impl LinkCollector<'_, '_> { ) { // The resolved item did not match the disambiguator; give a better error than 'not found' let msg = format!("incompatible link kind for `{}`", path_str); - let callback = |diag: &mut DiagnosticBuilder<'_>, sp: Option<rustc_span::Span>| { + let callback = |diag: &mut Diagnostic, sp: Option<rustc_span::Span>| { let note = format!( "this link resolved to {} {}, which is not {} {}", resolved.article(), @@ -1866,7 +1866,7 @@ fn report_diagnostic( lint: &'static Lint, msg: &str, DiagnosticInfo { item, ori_link: _, dox, link_range }: &DiagnosticInfo<'_>, - decorate: impl FnOnce(&mut DiagnosticBuilder<'_>, Option<rustc_span::Span>), + decorate: impl FnOnce(&mut Diagnostic, Option<rustc_span::Span>), ) { let hir_id = match DocContext::as_local_hir_id(tcx, item.def_id) { Some(hir_id) => hir_id, @@ -2098,8 +2098,15 @@ fn resolution_failure( ) } ResolutionFailure::NoParentItem => { - diag.level = rustc_errors::Level::Bug; - "all intra-doc links should have a parent item".to_owned() + // FIXME(eddyb) this doesn't belong here, whatever made + // the `ResolutionFailure::NoParentItem` should emit an + // immediate or delayed `span_bug` about the issue. + tcx.sess.delay_span_bug( + sp.unwrap_or(DUMMY_SP), + "intra-doc link missing parent item", + ); + + "BUG: all intra-doc links should have a parent item".to_owned() } ResolutionFailure::MalformedGenerics(variant) => match variant { MalformedGenerics::UnbalancedAngleBrackets => { @@ -2233,7 +2240,7 @@ fn ambiguity_error( /// disambiguator. fn suggest_disambiguator( res: Res, - diag: &mut DiagnosticBuilder<'_>, + diag: &mut Diagnostic, path_str: &str, ori_link: &str, sp: Option<rustc_span::Span>, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index e8b3a0929db..1693034db0e 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -325,7 +325,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om.items.push((item, renamed)) } - hir::ItemKind::Macro(ref macro_def) => { + hir::ItemKind::Macro(ref macro_def, _) => { // `#[macro_export] macro_rules!` items are handled seperately in `visit()`, // above, since they need to be documented at the module top level. Accordingly, // we only want to handle macros if one of three conditions holds: diff --git a/src/test/codegen/swap-large-types.rs b/src/test/codegen/swap-large-types.rs new file mode 100644 index 00000000000..535d301a3d2 --- /dev/null +++ b/src/test/codegen/swap-large-types.rs @@ -0,0 +1,64 @@ +// compile-flags: -O +// only-x86_64 +// ignore-debug: the debug assertions get in the way + +#![crate_type = "lib"] + +use std::mem::swap; +use std::ptr::{read, copy_nonoverlapping, write}; + +type KeccakBuffer = [[u64; 5]; 5]; + +// A basic read+copy+write swap implementation ends up copying one of the values +// to stack for large types, which is completely unnecessary as the lack of +// overlap means we can just do whatever fits in registers at a time. + +// CHECK-LABEL: @swap_basic +#[no_mangle] +pub fn swap_basic(x: &mut KeccakBuffer, y: &mut KeccakBuffer) { +// CHECK: alloca [5 x [5 x i64]] + + // SAFETY: exclusive references are always valid to read/write, + // are non-overlapping, and nothing here panics so it's drop-safe. + unsafe { + let z = read(x); + copy_nonoverlapping(y, x, 1); + write(y, z); + } +} + +// This test verifies that the library does something smarter, and thus +// doesn't need any scratch space on the stack. + +// CHECK-LABEL: @swap_std +#[no_mangle] +pub fn swap_std(x: &mut KeccakBuffer, y: &mut KeccakBuffer) { +// CHECK-NOT: alloca +// CHECK: load <{{[0-9]+}} x i64> +// CHECK: store <{{[0-9]+}} x i64> + swap(x, y) +} + +// CHECK-LABEL: @swap_slice +#[no_mangle] +pub fn swap_slice(x: &mut [KeccakBuffer], y: &mut [KeccakBuffer]) { +// CHECK-NOT: alloca +// CHECK: load <{{[0-9]+}} x i64> +// CHECK: store <{{[0-9]+}} x i64> + if x.len() == y.len() { + x.swap_with_slice(y); + } +} + +type OneKilobyteBuffer = [u8; 1024]; + +// CHECK-LABEL: @swap_1kb_slices +#[no_mangle] +pub fn swap_1kb_slices(x: &mut [OneKilobyteBuffer], y: &mut [OneKilobyteBuffer]) { +// CHECK-NOT: alloca +// CHECK: load <{{[0-9]+}} x i8> +// CHECK: store <{{[0-9]+}} x i8> + if x.len() == y.len() { + x.swap_with_slice(y); + } +} diff --git a/src/test/codegen/swap-simd-types.rs b/src/test/codegen/swap-simd-types.rs new file mode 100644 index 00000000000..c90b277eb44 --- /dev/null +++ b/src/test/codegen/swap-simd-types.rs @@ -0,0 +1,32 @@ +// compile-flags: -O -C target-feature=+avx +// only-x86_64 +// ignore-debug: the debug assertions get in the way + +#![crate_type = "lib"] + +use std::mem::swap; + +// SIMD types are highly-aligned already, so make sure the swap code leaves their +// types alone and doesn't pessimize them (such as by swapping them as `usize`s). +extern crate core; +use core::arch::x86_64::__m256; + +// CHECK-LABEL: @swap_single_m256 +#[no_mangle] +pub fn swap_single_m256(x: &mut __m256, y: &mut __m256) { +// CHECK-NOT: alloca +// CHECK: load <8 x float>{{.+}}align 32 +// CHECK: store <8 x float>{{.+}}align 32 + swap(x, y) +} + +// CHECK-LABEL: @swap_m256_slice +#[no_mangle] +pub fn swap_m256_slice(x: &mut [__m256], y: &mut [__m256]) { +// CHECK-NOT: alloca +// CHECK: load <8 x float>{{.+}}align 32 +// CHECK: store <8 x float>{{.+}}align 32 + if x.len() == y.len() { + x.swap_with_slice(y); + } +} diff --git a/src/test/codegen/swap-small-types.rs b/src/test/codegen/swap-small-types.rs index 6205e6a6559..2f375844cc7 100644 --- a/src/test/codegen/swap-small-types.rs +++ b/src/test/codegen/swap-small-types.rs @@ -16,3 +16,47 @@ pub fn swap_rgb48(x: &mut RGB48, y: &mut RGB48) { // CHECK: store i48 swap(x, y) } + +// LLVM doesn't vectorize a loop over 3-byte elements, +// so we chunk it down to bytes and loop over those instead. +type RGB24 = [u8; 3]; + +// CHECK-LABEL: @swap_rgb24_slices +#[no_mangle] +pub fn swap_rgb24_slices(x: &mut [RGB24], y: &mut [RGB24]) { +// CHECK-NOT: alloca +// CHECK: load <{{[0-9]+}} x i8> +// CHECK: store <{{[0-9]+}} x i8> + if x.len() == y.len() { + x.swap_with_slice(y); + } +} + +// This one has a power-of-two size, so we iterate over it directly +type RGBA32 = [u8; 4]; + +// CHECK-LABEL: @swap_rgba32_slices +#[no_mangle] +pub fn swap_rgba32_slices(x: &mut [RGBA32], y: &mut [RGBA32]) { +// CHECK-NOT: alloca +// CHECK: load <{{[0-9]+}} x i32> +// CHECK: store <{{[0-9]+}} x i32> + if x.len() == y.len() { + x.swap_with_slice(y); + } +} + +// Strings have a non-power-of-two size, but have pointer alignment, +// so we swap usizes instead of dropping all the way down to bytes. +const _: () = assert!(!std::mem::size_of::<String>().is_power_of_two()); + +// CHECK-LABEL: @swap_string_slices +#[no_mangle] +pub fn swap_string_slices(x: &mut [String], y: &mut [String]) { +// CHECK-NOT: alloca +// CHECK: load <{{[0-9]+}} x i64> +// CHECK: store <{{[0-9]+}} x i64> + if x.len() == y.len() { + x.swap_with_slice(y); + } +} diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 8b0cebfa60e..a37d3a32571 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -42,7 +42,7 @@ fn parse_expr(ps: &ParseSess, src: &str) -> Option<P<Expr>> { let mut p = new_parser_from_source_str(ps, FileName::Custom(src_as_string.clone()), src_as_string); - p.parse_expr().map_err(|mut e| e.cancel()).ok() + p.parse_expr().map_err(|e| e.cancel()).ok() } // Helper functions for building exprs diff --git a/src/test/ui/auto-traits/suspicious-impls-lint.rs b/src/test/ui/auto-traits/suspicious-impls-lint.rs index 1026a35a455..1574a7e02e9 100644 --- a/src/test/ui/auto-traits/suspicious-impls-lint.rs +++ b/src/test/ui/auto-traits/suspicious-impls-lint.rs @@ -1,5 +1,7 @@ #![deny(suspicious_auto_trait_impls)] +use std::marker::PhantomData; + struct MayImplementSendOk<T>(T); unsafe impl<T: Send> Send for MayImplementSendOk<T> {} // ok @@ -31,4 +33,12 @@ unsafe impl<T: Send> Send for TwoParamsSame<T, T> {} //~^ ERROR //~| WARNING this will change its meaning +pub struct WithPhantomDataNonSend<T, U>(PhantomData<*const T>, U); +unsafe impl<T> Send for WithPhantomDataNonSend<T, i8> {} // ok + +pub struct WithPhantomDataSend<T, U>(PhantomData<T>, U); +unsafe impl<T> Send for WithPhantomDataSend<*const T, i8> {} +//~^ ERROR +//~| WARNING this will change its meaning + fn main() {} diff --git a/src/test/ui/auto-traits/suspicious-impls-lint.stderr b/src/test/ui/auto-traits/suspicious-impls-lint.stderr index f91aa862271..084bfef49c0 100644 --- a/src/test/ui/auto-traits/suspicious-impls-lint.stderr +++ b/src/test/ui/auto-traits/suspicious-impls-lint.stderr @@ -1,5 +1,5 @@ error: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/suspicious-impls-lint.rs:7:1 + --> $DIR/suspicious-impls-lint.rs:9:1 | LL | unsafe impl<T: Send> Send for MayImplementSendErr<&T> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,14 +12,14 @@ LL | #![deny(suspicious_auto_trait_impls)] = warning: this will change its meaning in a future release! = note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367> note: try using the same sequence of generic parameters as the struct definition - --> $DIR/suspicious-impls-lint.rs:6:1 + --> $DIR/suspicious-impls-lint.rs:8:1 | LL | struct MayImplementSendErr<T>(T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `&T` is not a generic parameter error: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/suspicious-impls-lint.rs:19:1 + --> $DIR/suspicious-impls-lint.rs:21:1 | LL | unsafe impl Send for ContainsVec<i32> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,14 +27,14 @@ LL | unsafe impl Send for ContainsVec<i32> {} = warning: this will change its meaning in a future release! = note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367> note: try using the same sequence of generic parameters as the struct definition - --> $DIR/suspicious-impls-lint.rs:18:1 + --> $DIR/suspicious-impls-lint.rs:20:1 | LL | struct ContainsVec<T>(Vec<T>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `i32` is not a generic parameter error: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/suspicious-impls-lint.rs:30:1 + --> $DIR/suspicious-impls-lint.rs:32:1 | LL | unsafe impl<T: Send> Send for TwoParamsSame<T, T> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,11 +42,26 @@ LL | unsafe impl<T: Send> Send for TwoParamsSame<T, T> {} = warning: this will change its meaning in a future release! = note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367> note: try using the same sequence of generic parameters as the struct definition - --> $DIR/suspicious-impls-lint.rs:29:1 + --> $DIR/suspicious-impls-lint.rs:31:1 | LL | struct TwoParamsSame<T, U>(T, U); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `T` is mentioned multiple times -error: aborting due to 3 previous errors +error: cross-crate traits with a default impl, like `Send`, should not be specialized + --> $DIR/suspicious-impls-lint.rs:40:1 + | +LL | unsafe impl<T> Send for WithPhantomDataSend<*const T, i8> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367> +note: try using the same sequence of generic parameters as the struct definition + --> $DIR/suspicious-impls-lint.rs:39:1 + | +LL | pub struct WithPhantomDataSend<T, U>(PhantomData<T>, U); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `*const T` is not a generic parameter + +error: aborting due to 4 previous errors diff --git a/src/test/ui/check-cfg/invalid-cfg-name.stderr b/src/test/ui/check-cfg/invalid-cfg-name.stderr index 2587685afa0..2bd1821c942 100644 --- a/src/test/ui/check-cfg/invalid-cfg-name.stderr +++ b/src/test/ui/check-cfg/invalid-cfg-name.stderr @@ -2,7 +2,7 @@ warning: unexpected `cfg` condition name --> $DIR/invalid-cfg-name.rs:7:7 | LL | #[cfg(widnows)] - | ^^^^^^^ + | ^^^^^^^ help: did you mean: `windows` | = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/src/test/ui/check-cfg/invalid-cfg-value.stderr b/src/test/ui/check-cfg/invalid-cfg-value.stderr index c591d8474a2..bc2c053fed6 100644 --- a/src/test/ui/check-cfg/invalid-cfg-value.stderr +++ b/src/test/ui/check-cfg/invalid-cfg-value.stderr @@ -5,6 +5,7 @@ LL | #[cfg(feature = "sedre")] | ^^^^^^^^^^^^^^^^^ | = note: `#[warn(unexpected_cfgs)]` on by default + = note: expected values for `feature` are: full, rand, serde warning: 1 warning emitted diff --git a/src/test/ui/check-cfg/mix.rs b/src/test/ui/check-cfg/mix.rs new file mode 100644 index 00000000000..26c735c4a10 --- /dev/null +++ b/src/test/ui/check-cfg/mix.rs @@ -0,0 +1,50 @@ +// This test checks the combination of well known names, their activation via names(), the usage of +// partial values() with a --cfg and test that we also correctly lint on the `cfg!` macro and +// `cfg_attr` attribute. +// +// check-pass +// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --cfg feature="bar" -Z unstable-options + +#[cfg(windows)] +fn do_windows_stuff() {} + +#[cfg(widnows)] +//~^ WARNING unexpected `cfg` condition name +fn do_windows_stuff() {} + +#[cfg(feature = "foo")] +fn use_foo() {} + +#[cfg(feature = "bar")] +fn use_bar() {} + +#[cfg(feature = "zebra")] +//~^ WARNING unexpected `cfg` condition value +fn use_zebra() {} + +#[cfg_attr(uu, test)] +//~^ WARNING unexpected `cfg` condition name +fn do_test() {} + +#[cfg_attr(feature = "foo", no_mangle)] +fn do_test_foo() {} + +fn test_cfg_macro() { + cfg!(windows); + cfg!(widnows); + //~^ WARNING unexpected `cfg` condition name + cfg!(feature = "foo"); + cfg!(feature = "bar"); + cfg!(feature = "zebra"); + //~^ WARNING unexpected `cfg` condition value + cfg!(xxx = "foo"); + //~^ WARNING unexpected `cfg` condition name + cfg!(xxx); + //~^ WARNING unexpected `cfg` condition name + cfg!(any(xxx, windows)); + //~^ WARNING unexpected `cfg` condition name + cfg!(any(feature = "bad", windows)); + //~^ WARNING unexpected `cfg` condition value +} + +fn main() {} diff --git a/src/test/ui/check-cfg/mix.stderr b/src/test/ui/check-cfg/mix.stderr new file mode 100644 index 00000000000..b273be77422 --- /dev/null +++ b/src/test/ui/check-cfg/mix.stderr @@ -0,0 +1,66 @@ +warning: unexpected `cfg` condition name + --> $DIR/mix.rs:11:7 + | +LL | #[cfg(widnows)] + | ^^^^^^^ help: did you mean: `windows` + | + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition value + --> $DIR/mix.rs:21:7 + | +LL | #[cfg(feature = "zebra")] + | ^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: bar, foo + +warning: unexpected `cfg` condition name + --> $DIR/mix.rs:25:12 + | +LL | #[cfg_attr(uu, test)] + | ^^ + +warning: unexpected `cfg` condition name + --> $DIR/mix.rs:34:10 + | +LL | cfg!(widnows); + | ^^^^^^^ help: did you mean: `windows` + +warning: unexpected `cfg` condition value + --> $DIR/mix.rs:38:10 + | +LL | cfg!(feature = "zebra"); + | ^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: bar, foo + +warning: unexpected `cfg` condition name + --> $DIR/mix.rs:40:10 + | +LL | cfg!(xxx = "foo"); + | ^^^^^^^^^^^ + +warning: unexpected `cfg` condition name + --> $DIR/mix.rs:42:10 + | +LL | cfg!(xxx); + | ^^^ + +warning: unexpected `cfg` condition name + --> $DIR/mix.rs:44:14 + | +LL | cfg!(any(xxx, windows)); + | ^^^ + +warning: unexpected `cfg` condition value + --> $DIR/mix.rs:46:14 + | +LL | cfg!(any(feature = "bad", windows)); + | ^^^^^^^^^^----- + | | + | help: did you mean: `"bar"` + | + = note: expected values for `feature` are: bar, foo + +warning: 9 warnings emitted + diff --git a/src/test/ui/check-cfg/no-values.rs b/src/test/ui/check-cfg/no-values.rs new file mode 100644 index 00000000000..2440757e52d --- /dev/null +++ b/src/test/ui/check-cfg/no-values.rs @@ -0,0 +1,10 @@ +// Check that we detect unexpected value when none are allowed +// +// check-pass +// compile-flags: --check-cfg=values(feature) -Z unstable-options + +#[cfg(feature = "foo")] +//~^ WARNING unexpected `cfg` condition value +fn do_foo() {} + +fn main() {} diff --git a/src/test/ui/check-cfg/no-values.stderr b/src/test/ui/check-cfg/no-values.stderr new file mode 100644 index 00000000000..ea1c9107d4c --- /dev/null +++ b/src/test/ui/check-cfg/no-values.stderr @@ -0,0 +1,11 @@ +warning: unexpected `cfg` condition value + --> $DIR/no-values.rs:6:7 + | +LL | #[cfg(feature = "foo")] + | ^^^^^^^^^^^^^^^ + | + = note: `#[warn(unexpected_cfgs)]` on by default + = note: no expected value for `feature` + +warning: 1 warning emitted + diff --git a/src/test/ui/check-cfg/well-known-names.rs b/src/test/ui/check-cfg/well-known-names.rs new file mode 100644 index 00000000000..a66568a2ffd --- /dev/null +++ b/src/test/ui/check-cfg/well-known-names.rs @@ -0,0 +1,27 @@ +// This test checks that we lint on non well known names and that we don't lint on well known names +// +// check-pass +// compile-flags: --check-cfg=names() -Z unstable-options + +#[cfg(target_oz = "linux")] +//~^ WARNING unexpected `cfg` condition name +fn target_os_misspell() {} + +#[cfg(target_os = "linux")] +fn target_os() {} + +#[cfg(features = "foo")] +//~^ WARNING unexpected `cfg` condition name +fn feature_misspell() {} + +#[cfg(feature = "foo")] +fn feature() {} + +#[cfg(uniw)] +//~^ WARNING unexpected `cfg` condition name +fn unix_misspell() {} + +#[cfg(unix)] +fn unix() {} + +fn main() {} diff --git a/src/test/ui/check-cfg/well-known-names.stderr b/src/test/ui/check-cfg/well-known-names.stderr new file mode 100644 index 00000000000..bdbe4d29d30 --- /dev/null +++ b/src/test/ui/check-cfg/well-known-names.stderr @@ -0,0 +1,26 @@ +warning: unexpected `cfg` condition name + --> $DIR/well-known-names.rs:6:7 + | +LL | #[cfg(target_oz = "linux")] + | ---------^^^^^^^^^^ + | | + | help: did you mean: `target_os` + | + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition name + --> $DIR/well-known-names.rs:13:7 + | +LL | #[cfg(features = "foo")] + | --------^^^^^^^^ + | | + | help: did you mean: `feature` + +warning: unexpected `cfg` condition name + --> $DIR/well-known-names.rs:20:7 + | +LL | #[cfg(uniw)] + | ^^^^ help: did you mean: `unix` + +warning: 3 warnings emitted + diff --git a/src/test/ui/debuginfo-emit-llvm-ir-and-split-debuginfo.rs b/src/test/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs index 043011b3316..043011b3316 100644 --- a/src/test/ui/debuginfo-emit-llvm-ir-and-split-debuginfo.rs +++ b/src/test/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs diff --git a/src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs b/src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs new file mode 100644 index 00000000000..833a4726acb --- /dev/null +++ b/src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs @@ -0,0 +1,29 @@ +// check-pass +// compile-flags: -Cdebuginfo=2 +// fixes issue #94149 + +#![allow(dead_code)] + +pub fn main() { + let _ = Foo::<dyn FooTrait>::new(); +} + +pub struct Foo<T: FooTrait + ?Sized> { + base: FooBase, + value: T, +} + +impl<T: FooTrait + ?Sized> Foo<T> { + pub fn new() -> Box<Foo<T>> { + todo!() + } +} + +pub trait FooTrait {} + +pub struct FooBase { + cls: Bar, +} + +// Bar *must* be a fieldless enum +pub enum Bar {} diff --git a/src/test/ui/traits/copy-impl-cannot-normalize.rs b/src/test/ui/traits/copy-impl-cannot-normalize.rs new file mode 100644 index 00000000000..a78ff046e97 --- /dev/null +++ b/src/test/ui/traits/copy-impl-cannot-normalize.rs @@ -0,0 +1,25 @@ +trait TraitFoo { + type Bar; +} + +struct Foo<T> +where + T: TraitFoo, +{ + inner: T::Bar, +} + +impl<T> Clone for Foo<T> +where + T: TraitFoo, + T::Bar: Clone, +{ + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } +} + +impl<T> Copy for Foo<T> {} +//~^ ERROR the trait bound `T: TraitFoo` is not satisfied + +fn main() {} diff --git a/src/test/ui/traits/copy-impl-cannot-normalize.stderr b/src/test/ui/traits/copy-impl-cannot-normalize.stderr new file mode 100644 index 00000000000..cc540ea905a --- /dev/null +++ b/src/test/ui/traits/copy-impl-cannot-normalize.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `T: TraitFoo` is not satisfied + --> $DIR/copy-impl-cannot-normalize.rs:22:1 + | +LL | impl<T> Copy for Foo<T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitFoo` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | impl<T: TraitFoo> Copy for Foo<T> {} + | ++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 8b79f1600ae..a20aa12c9ff 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -6,7 +6,7 @@ use clippy_utils::{ }; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Block, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -489,7 +489,7 @@ fn emit_branches_sharing_code_lint( add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit(); } - let add_optional_msgs = |diag: &mut DiagnosticBuilder<'_>| { + let add_optional_msgs = |diag: &mut Diagnostic| { if add_expr_note { diag.note("The end suggestion probably needs some adjustments to use the expression result correctly"); } diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index a00361e6062..16173580fd4 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -628,9 +628,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) { let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) { Ok(p) => p, Err(errs) => { - for mut err in errs { - err.cancel(); - } + drop(errs); return false; }, }; @@ -668,7 +666,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) { _ => {}, }, Ok(None) => break, - Err(mut e) => { + Err(e) => { e.cancel(); return false; }, diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index 5e4cde553b5..d5430a8c917 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use std::collections::BTreeMap; -use rustc_errors::DiagnosticBuilder; +use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor}; use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind}; @@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { fn suggestion<'tcx>( cx: &LateContext<'tcx>, - diag: &mut DiagnosticBuilder<'_>, + diag: &mut Diagnostic, generics_span: Span, generics_suggestion_span: Span, target: &ImplicitHasherType<'_>, diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs index df69d3dcc51..dd7177e0131 100644 --- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs +++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs @@ -1,7 +1,7 @@ //! checks for `#[inline]` on trait methods without bodies use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::sugg::DiagnosticBuilderExt; +use clippy_utils::sugg::DiagnosticExt; use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index ebd4fb0bf51..ebfd908a6fb 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -6,7 +6,7 @@ use clippy_utils::{get_trait_def_id, is_self, paths}; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::intravisit::FnKind; use rustc_hir::{BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Node, PatKind, QPath, TyKind}; use rustc_hir::{HirIdMap, HirIdSet}; @@ -196,10 +196,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } // Dereference suggestion - let sugg = |diag: &mut DiagnosticBuilder<'_>| { + let sugg = |diag: &mut Diagnostic| { if let ty::Adt(def, ..) = ty.kind() { if let Some(span) = cx.tcx.hir().span_if_local(def.did) { - if can_type_implement_copy(cx.tcx, cx.param_env, ty).is_ok() { + if can_type_implement_copy(cx.tcx, cx.param_env, ty, traits::ObligationCause::dummy_with_span(span)).is_ok() { diag.span_help(span, "consider marking this type as `Copy`"); } } diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index f86af7a7bb6..4cb79648ae3 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::return_ty; use clippy_utils::source::snippet; -use clippy_utils::sugg::DiagnosticBuilderExt; +use clippy_utils::sugg::DiagnosticExt; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index 86911483137..dc48ea3f4f9 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -373,7 +373,7 @@ fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) { let item_ty = cx.tcx.type_of(did); println!("function of type {:#?}", item_ty); }, - hir::ItemKind::Macro(ref macro_def) => { + hir::ItemKind::Macro(ref macro_def, _) => { if macro_def.macro_rules { println!("macro introduced by `macro_rules!`"); } else { diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 1fa6301ebd7..a328ddda5ae 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -534,7 +534,7 @@ impl Write { match parser .parse_expr() .map(rustc_ast::ptr::P::into_inner) - .map_err(|mut e| e.cancel()) + .map_err(|e| e.cancel()) { // write!(e, ...) Ok(p) if parser.eat(&token::Comma) => Some(p), @@ -563,7 +563,7 @@ impl Write { } let comma_span = parser.prev_token.span; - let token_expr = if let Ok(expr) = parser.parse_expr().map_err(|mut err| err.cancel()) { + let token_expr = if let Ok(expr) = parser.parse_expr().map_err(|err| err.cancel()) { expr } else { return (Some(fmtstr), None); diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index ca222c3d669..a927788e6a4 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -8,13 +8,13 @@ //! Thank you! //! ~The `INTERNAL_METADATA_COLLECTOR` lint -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::HirId; use rustc_lint::{LateContext, Lint, LintContext}; use rustc_span::source_map::{MultiSpan, Span}; use std::env; -fn docs_link(diag: &mut DiagnosticBuilder<'_>, lint: &'static Lint) { +fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) { if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() { if let Some(lint) = lint.name_lower().strip_prefix("clippy::") { diag.help(&format!( @@ -145,7 +145,7 @@ pub fn span_lint_and_then<C, S, F>(cx: &C, lint: &'static Lint, sp: S, msg: &str where C: LintContext, S: Into<MultiSpan>, - F: FnOnce(&mut DiagnosticBuilder<'_>), + F: FnOnce(&mut Diagnostic), { cx.struct_span_lint(lint, sp, |diag| { let mut diag = diag.build(msg); @@ -169,7 +169,7 @@ pub fn span_lint_hir_and_then( hir_id: HirId, sp: impl Into<MultiSpan>, msg: &str, - f: impl FnOnce(&mut DiagnosticBuilder<'_>), + f: impl FnOnce(&mut Diagnostic), ) { cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| { let mut diag = diag.build(msg); @@ -219,7 +219,7 @@ pub fn span_lint_and_sugg<'a, T: LintContext>( /// appear once per /// replacement. In human-readable format though, it only appears once before /// the whole suggestion. -pub fn multispan_sugg<I>(diag: &mut DiagnosticBuilder<'_>, help_msg: &str, sugg: I) +pub fn multispan_sugg<I>(diag: &mut Diagnostic, help_msg: &str, sugg: I) where I: IntoIterator<Item = (Span, String)>, { @@ -232,7 +232,7 @@ where /// multiple spans. This is tracked in issue [rustfix#141](https://github.com/rust-lang/rustfix/issues/141). /// Suggestions with multiple spans will be silently ignored. pub fn multispan_sugg_with_applicability<I>( - diag: &mut DiagnosticBuilder<'_>, + diag: &mut Diagnostic, help_msg: &str, applicability: Applicability, sugg: I, diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index fa63ddff253..63c442e7008 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -673,8 +673,8 @@ fn indentation<T: LintContext>(cx: &T, span: Span) -> Option<String> { }) } -/// Convenience extension trait for `DiagnosticBuilder`. -pub trait DiagnosticBuilderExt<T: LintContext> { +/// Convenience extension trait for `Diagnostic`. +pub trait DiagnosticExt<T: LintContext> { /// Suggests to add an attribute to an item. /// /// Correctly handles indentation of the attribute and item. @@ -721,7 +721,7 @@ pub trait DiagnosticBuilderExt<T: LintContext> { fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability: Applicability); } -impl<T: LintContext> DiagnosticBuilderExt<T> for rustc_errors::DiagnosticBuilder<'_> { +impl<T: LintContext> DiagnosticExt<T> for rustc_errors::Diagnostic { fn suggest_item_with_attr<D: Display + ?Sized>( &mut self, cx: &T, diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed index 306ea50258d..a83c8ba0b64 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.fixed +++ b/src/tools/clippy/tests/ui/macro_use_imports.fixed @@ -15,7 +15,7 @@ extern crate macro_use_helper as mac; extern crate proc_macro_derive as mini_mac; mod a { - use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro}; + use mac::{pub_macro, function_macro, ty_macro, inner_mod_macro, pub_in_private_macro}; use mac; use mini_mac::ClippyMiniMacroTest; use mini_mac; diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr index f8c86c8d917..9028a636e7f 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.stderr +++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr @@ -2,7 +2,7 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:18:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, function_macro, ty_macro, inner_mod_macro, pub_in_private_macro};` | = note: `-D clippy::macro-use-imports` implied by `-D warnings` diff --git a/src/tools/rustfmt/src/modules.rs b/src/tools/rustfmt/src/modules.rs index 9c964b274e0..d4bddd95785 100644 --- a/src/tools/rustfmt/src/modules.rs +++ b/src/tools/rustfmt/src/modules.rs @@ -439,7 +439,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> { } } Err(mod_err) if !mods_outside_ast.is_empty() => { - if let ModError::ParserError(mut e) = mod_err { + if let ModError::ParserError(e) = mod_err { e.cancel(); } Ok(Some(SubModKind::MultiExternal(mods_outside_ast))) diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs index e10fbe64bcd..306b6bb745e 100644 --- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs +++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs @@ -57,7 +57,7 @@ fn parse_cfg_if_inner<'a>( let item = match parser.parse_item(ForceCollect::No) { Ok(Some(item_ptr)) => item_ptr.into_inner(), Ok(None) => continue, - Err(mut err) => { + Err(err) => { err.cancel(); parser.sess.span_diagnostic.reset_err_count(); return Err( diff --git a/src/tools/rustfmt/src/parse/macros/lazy_static.rs b/src/tools/rustfmt/src/parse/macros/lazy_static.rs index 9c8651aa3fa..4c541de04be 100644 --- a/src/tools/rustfmt/src/parse/macros/lazy_static.rs +++ b/src/tools/rustfmt/src/parse/macros/lazy_static.rs @@ -23,7 +23,7 @@ pub(crate) fn parse_lazy_static( val } } - Err(mut err) => { + Err(err) => { err.cancel(); parser.sess.span_diagnostic.reset_err_count(); return None; diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs index 2e9ce1d35f4..fd738908170 100644 --- a/src/tools/rustfmt/src/parse/macros/mod.rs +++ b/src/tools/rustfmt/src/parse/macros/mod.rs @@ -36,7 +36,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> { return Some(MacroArg::$macro_arg($f(x)?)); } } - Err(mut e) => { + Err(e) => { e.cancel(); parser.sess.span_diagnostic.reset_err_count(); } diff --git a/src/tools/rustfmt/src/parse/parser.rs b/src/tools/rustfmt/src/parse/parser.rs index 657217633f4..f0944a88d2f 100644 --- a/src/tools/rustfmt/src/parse/parser.rs +++ b/src/tools/rustfmt/src/parse/parser.rs @@ -115,7 +115,7 @@ impl<'a> Parser<'a> { match parser.parse_mod(&TokenKind::Eof) { Ok(result) => Some(result), Err(mut e) => { - sess.emit_or_cancel_diagnostic(&mut e); + e.emit(); if sess.can_reset_errors() { sess.reset_errors(); } diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index 7fc3778376c..40a6d708d8c 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -60,7 +60,7 @@ impl Emitter for SilentOnIgnoredFilesEmitter { None } fn emit_diagnostic(&mut self, db: &Diagnostic) { - if db.level == DiagnosticLevel::Fatal { + if db.level() == DiagnosticLevel::Fatal { return self.handle_non_ignoreable_error(db); } if let Some(primary_span) = &db.span.primary_span() { @@ -230,17 +230,6 @@ impl ParseSess { } } - pub(crate) fn emit_or_cancel_diagnostic(&self, diagnostic: &mut Diagnostic) { - self.parse_sess.span_diagnostic.emit_diagnostic(diagnostic); - // The Handler will check whether the diagnostic should be emitted - // based on the user's rustfmt configuration and the originating file - // that caused the parser error. If the Handler determined it should skip - // emission then we need to ensure the diagnostic is cancelled. - if !diagnostic.cancelled() { - diagnostic.cancel(); - } - } - pub(super) fn can_reset_errors(&self) -> bool { self.can_reset_errors.load(Ordering::Acquire) } @@ -292,7 +281,7 @@ mod tests { use super::*; use crate::config::IgnoreList; use crate::utils::mk_sp; - use rustc_span::{FileName as SourceMapFileName, MultiSpan, RealFileName, DUMMY_SP}; + use rustc_span::{FileName as SourceMapFileName, MultiSpan, RealFileName}; use std::path::PathBuf; use std::sync::atomic::AtomicU32; @@ -310,16 +299,12 @@ mod tests { } fn build_diagnostic(level: DiagnosticLevel, span: Option<MultiSpan>) -> Diagnostic { - Diagnostic { - level, - code: None, - message: vec![], - children: vec![], - suggestions: Ok(vec![]), - span: span.unwrap_or_else(MultiSpan::new), - sort_span: DUMMY_SP, - is_lint: false, + let mut diag = Diagnostic::new(level, ""); + diag.message.clear(); + if let Some(span) = span { + diag.span = span; } + diag } fn build_emitter( |
