diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index df949e46fbd..632f819e584 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -555,18 +555,6 @@ impl Diagnostic { self } - /// Help the user upgrade to the latest edition. - /// This is factored out to make sure it does the right thing with `Cargo.toml`. - pub fn help_use_latest_edition(&mut self) -> &mut Self { - if std::env::var_os("CARGO").is_some() { - self.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION)); - } else { - self.help(&format!("pass `--edition {}` to `rustc`", LATEST_STABLE_EDITION)); - } - self.note("for more on editions, read https://doc.rust-lang.org/edition-guide"); - self - } - /// Disallow attaching suggestions this diagnostic. /// Any suggestions attached e.g. with the `span_suggestion_*` methods /// (before and after the call to `disable_suggestions`) will be ignored. @@ -1083,3 +1071,39 @@ impl PartialEq for Diagnostic { self.keys() == other.keys() } } + +pub enum HelpUseLatestEdition { + Cargo, + Standalone, +} + +impl HelpUseLatestEdition { + pub fn new() -> Self { + if std::env::var_os("CARGO").is_some() { Self::Cargo } else { Self::Standalone } + } +} + +impl AddToDiagnostic for HelpUseLatestEdition { + fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, + { + let msg = f( + diag, + match self { + Self::Cargo => { + format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION) + } + Self::Standalone => { + format!("pass `--edition {}` to `rustc`", LATEST_STABLE_EDITION) + } + } + .into(), + ); + diag.help(msg); + + let msg = + f(diag, "for more on editions, read https://doc.rust-lang.org/edition-guide".into()); + diag.note(msg); + } +} diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index c9d662ad43f..3064d2bedbe 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -669,7 +669,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { sp: impl Into, msg: impl Into, ) -> &mut Self); - forward!(pub fn help_use_latest_edition(&mut self,) -> &mut Self); forward!(pub fn set_is_lint(&mut self,) -> &mut Self); forward!(pub fn disable_suggestions(&mut self,) -> &mut Self); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index ec04e865d53..05cfebbfe8a 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -378,7 +378,7 @@ pub struct DelayedBugPanic; pub use diagnostic::{ AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, - DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, + DiagnosticStyledString, HelpUseLatestEdition, IntoDiagnosticArg, SubDiagnostic, }; pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted}; pub use diagnostic_impls::{DiagnosticArgFromDisplay, DiagnosticSymbolList}; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 74913bac724..3054e1c8ac2 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -23,8 +23,8 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ - pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, - ErrorGuaranteed, StashKey, + pluralize, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, + DiagnosticId, ErrorGuaranteed, HelpUseLatestEdition, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -2433,7 +2433,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We know by construction that `.await` is either on Rust 2015 // or results in `ExprKind::Await`. Suggest switching the edition to 2018. err.note("to `.await` a `Future`, switch to Rust 2018 or later"); - err.help_use_latest_edition(); + HelpUseLatestEdition::new().add_to_diagnostic(&mut err); } err.emit(); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 500d7d77071..ae59cb4bbe0 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -39,8 +39,8 @@ use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, R use rustc_ast::{ClosureBinder, MetaItemLit, StmtKind}; use rustc_ast_pretty::pprust; use rustc_errors::{ - Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult, - StashKey, + AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + HelpUseLatestEdition, IntoDiagnostic, PResult, StashKey, }; use rustc_session::errors::{report_lit_error, ExprParenthesesNeeded}; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; @@ -2927,7 +2927,7 @@ impl<'a> Parser<'a> { 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_use_latest_edition(); + HelpUseLatestEdition::new().add_to_diagnostic(e); }; while self.token != token::CloseDelim(close_delim) { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 4c918b283d7..d72c7d8cabc 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -16,7 +16,10 @@ use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, Vari use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind}; use rustc_ast::{MacCall, MacDelimiter}; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_err, Applicability, IntoDiagnostic, PResult, StashKey}; +use rustc_errors::{ + struct_span_err, AddToDiagnostic, Applicability, HelpUseLatestEdition, IntoDiagnostic, PResult, + StashKey, +}; use rustc_span::edition::Edition; use rustc_span::lev_distance::lev_distance; use rustc_span::source_map::{self, Span}; @@ -2445,10 +2448,12 @@ impl<'a> Parser<'a> { fn ban_async_in_2015(&self, span: Span) { if span.rust_2015() { let diag = self.diagnostic(); - struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015") - .span_label(span, "to use `async fn`, switch to Rust 2018 or later") - .help_use_latest_edition() - .emit(); + + let mut e = + struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015"); + e.span_label(span, "to use `async fn`, switch to Rust 2018 or later"); + HelpUseLatestEdition::new().add_to_diagnostic(&mut e); + e.emit(); } }