diff --git a/Cargo.lock b/Cargo.lock index 3a35985836c..cb245ce0ff8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3595,6 +3595,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_feature", + "rustc_macros", "rustc_parse", "rustc_session", "rustc_span", diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index 22742b2adbd..37eff9207c1 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -11,6 +11,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index e61dfef7bd3..b337e5328c5 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -13,7 +13,7 @@ use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{error_code, pluralize, struct_span_err, Applicability, Diagnostic}; +use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, @@ -27,6 +27,8 @@ use std::mem; use std::ops::{Deref, DerefMut}; +use crate::errors::*; + const MORE_EXTERN: &str = "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html"; @@ -117,23 +119,7 @@ fn with_let_management( /// Emits an error banning the `let` expression provided in the given location. fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) { - let err = "`let` expressions are not supported here"; - let mut diag = self.session.struct_span_err(expr.span, err); - diag.note("only supported directly in conditions of `if` and `while` expressions"); - match forbidden_let_reason { - ForbiddenLetReason::GenericForbidden => {} - ForbiddenLetReason::NotSupportedOr(span) => { - diag.span_note(span, "`||` operators are not supported in let chain expressions"); - } - ForbiddenLetReason::NotSupportedParentheses(span) => { - diag.span_note( - span, - "`let`s wrapped in parentheses are not supported in a context with let \ - chains", - ); - } - } - diag.emit(); + self.session.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason }); } fn check_gat_where( @@ -163,7 +149,7 @@ fn check_gat_where( DEPRECATED_WHERE_CLAUSE_LOCATION, id, where_clauses.0.1, - "where clause not allowed here", + fluent::ast_passes::deprecated_where_clause_location, BuiltinLintDiagnostics::DeprecatedWhereclauseLocation( where_clauses.1.1.shrink_to_hi(), suggestion, @@ -193,10 +179,7 @@ fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocCons AssocConstraintKind::Equality { .. } => {} AssocConstraintKind::Bound { .. } => { if self.is_assoc_ty_bound_banned { - self.err_handler().span_err( - constraint.span, - "associated type bounds are not allowed within structs, enums, or unions", - ); + self.session.emit_err(ForbiddenAssocConstraint { span: constraint.span }); } } } @@ -268,31 +251,26 @@ fn err_handler(&self) -> &rustc_errors::Handler { fn check_lifetime(&self, ident: Ident) { let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty]; if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { - self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names"); + self.session.emit_err(KeywordLifetime { span: ident.span }); } } fn check_label(&self, ident: Ident) { if ident.without_first_quote().is_reserved() { - self.err_handler() - .span_err(ident.span, &format!("invalid label name `{}`", ident.name)); + self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name }); } } - fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) { + fn invalid_visibility(&self, vis: &Visibility, note: Option) { if let VisibilityKind::Inherited = vis.kind { return; } - let mut err = - struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier"); - if vis.kind.is_pub() { - err.span_label(vis.span, "`pub` not permitted here because it's implied"); - } - if let Some(note) = note { - err.note(note); - } - err.emit(); + self.session.emit_err(InvalidVisibility { + span: vis.span, + implied: if vis.kind.is_pub() { Some(vis.span) } else { None }, + note, + }); } fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option, bool)) { @@ -309,29 +287,13 @@ fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option { if !param.bounds.is_empty() { let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); - self.err_handler() - .span_err(spans, "lifetime bounds cannot be used in this context"); + self.session.emit_err(ForbiddenLifetimeBound { spans }); } None } @@ -353,10 +314,7 @@ fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) { }) .collect(); if !non_lt_param_spans.is_empty() { - self.err_handler().span_err( - non_lt_param_spans, - "only lifetime parameters can be used in this context", - ); + self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans }); } } @@ -373,10 +331,7 @@ fn check_decl_num_args(&self, fn_decl: &FnDecl) { let max_num_args: usize = u16::MAX.into(); if fn_decl.inputs.len() > max_num_args { let Param { span, .. } = fn_decl.inputs[0]; - self.err_handler().span_fatal( - span, - &format!("function can not have more than {} arguments", max_num_args), - ); + self.session.emit_fatal(FnParamTooMany { span, max_num_args }); } } @@ -384,19 +339,13 @@ fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) { match &*fn_decl.inputs { [Param { ty, span, .. }] => { if let TyKind::CVarArgs = ty.kind { - self.err_handler().span_err( - *span, - "C-variadic function must be declared with at least one named argument", - ); + self.session.emit_err(FnParamCVarArgsOnly { span: *span }); } } [ps @ .., _] => { for Param { ty, span, .. } in ps { if let TyKind::CVarArgs = ty.kind { - self.err_handler().span_err( - *span, - "`...` must be the last argument of a C-variadic function", - ); + self.session.emit_err(FnParamCVarArgsNotLast { span: *span }); } } } @@ -423,19 +372,9 @@ fn check_decl_attrs(&self, fn_decl: &FnDecl) { }) .for_each(|attr| { if attr.is_doc_comment() { - self.err_handler() - .struct_span_err( - attr.span, - "documentation comments cannot be applied to function parameters", - ) - .span_label(attr.span, "doc comments are not allowed here") - .emit(); + self.session.emit_err(FnParamDocComment { span: attr.span }); } else { - self.err_handler().span_err( - attr.span, - "allow, cfg, cfg_attr, deny, expect, \ - forbid, and warn are the only allowed built-in attributes in function parameters", - ); + self.session.emit_err(FnParamForbiddenAttr { span: attr.span }); } }); } @@ -443,14 +382,7 @@ fn check_decl_attrs(&self, fn_decl: &FnDecl) { fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) { if param.is_self() { - self.err_handler() - .struct_span_err( - param.span, - "`self` parameter is only allowed in associated functions", - ) - .span_label(param.span, "not semantically valid as function parameter") - .note("associated functions are those in `impl` or `trait` definitions") - .emit(); + self.session.emit_err(FnParamForbiddenSelf { span: param.span }); } } } @@ -458,47 +390,20 @@ fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { fn check_defaultness(&self, span: Span, defaultness: Defaultness) { if let Defaultness::Default(def_span) = defaultness { let span = self.session.source_map().guess_head_span(span); - self.err_handler() - .struct_span_err(span, "`default` is only allowed on items in trait impls") - .span_label(def_span, "`default` because of this") - .emit(); + self.session.emit_err(ForbiddenDefault { span, def_span }); } } - fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) { - self.error_item_without_body_with_help(sp, ctx, msg, sugg, |_| ()); - } - - fn error_item_without_body_with_help( - &self, - sp: Span, - ctx: &str, - msg: &str, - sugg: &str, - help: impl FnOnce(&mut Diagnostic), - ) { + /// If `sp` ends with a semicolon, returns it as a `Span` + /// Otherwise, returns `sp.shrink_to_hi()` + fn ending_semi_or_hi(&self, sp: Span) -> Span { let source_map = self.session.source_map(); let end = source_map.end_point(sp); - let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) { + + if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) { end } else { sp.shrink_to_hi() - }; - let mut err = self.err_handler().struct_span_err(sp, msg); - err.span_suggestion( - replace_span, - &format!("provide a definition for the {}", ctx), - sugg, - Applicability::HasPlaceholders, - ); - help(&mut err); - err.emit(); - } - - fn check_impl_item_provided(&self, sp: Span, body: &Option, ctx: &str, sugg: &str) { - if body.is_none() { - let msg = format!("associated {} in `impl` without body", ctx); - self.error_item_without_body(sp, ctx, &msg, sugg); } } @@ -1168,7 +1073,7 @@ fn visit_item(&mut self, item: &'a Item) { self.invalid_visibility( &item.vis, - Some("place qualifiers on individual impl items instead"), + Some(InvalidVisibilityNote::IndividualImplItems), ); if let Unsafe::Yes(span) = unsafety { error(span, "unsafe").code(error_code!(E0197)).emit(); @@ -1191,37 +1096,23 @@ fn visit_item(&mut self, item: &'a Item) { self.check_defaultness(item.span, defaultness); if body.is_none() { - let msg = "free function without a body"; - let ext = sig.header.ext; - - let f = |e: &mut Diagnostic| { - if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext - { - let start_suggestion = if let Extern::Explicit(abi, _) = ext { - format!("extern \"{}\" {{", abi.symbol_unescaped) - } else { - "extern {".to_owned() - }; - - let end_suggestion = " }".to_owned(); - let end_span = item.span.shrink_to_hi(); - - e - .multipart_suggestion( - "if you meant to declare an externally defined function, use an `extern` block", - vec![(*start_span, start_suggestion), (end_span, end_suggestion)], - Applicability::MaybeIncorrect, - ); - } - }; - - self.error_item_without_body_with_help( - item.span, - "function", - msg, - " { }", - f, - ); + self.session.emit_err(FnWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + extern_block_suggestion: match sig.header.ext { + Extern::None => None, + Extern::Implicit(start_span) => Some(ExternBlockSuggestion { + start_span, + end_span: item.span.shrink_to_hi(), + abi: None, + }), + Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion { + start_span, + end_span: item.span.shrink_to_hi(), + abi: Some(abi.symbol_unescaped), + }), + }, + }); } self.visit_vis(&item.vis); @@ -1236,7 +1127,7 @@ fn visit_item(&mut self, item: &'a Item) { let old_item = mem::replace(&mut self.extern_mod, Some(item)); self.invalid_visibility( &item.vis, - Some("place qualifiers on individual foreign items instead"), + Some(InvalidVisibilityNote::IndividualForeignItems), ); if let Unsafe::Yes(span) = unsafety { self.err_handler().span_err(span, "extern block cannot be declared unsafe"); @@ -1327,12 +1218,16 @@ fn visit_item(&mut self, item: &'a Item) { } ItemKind::Const(def, .., None) => { self.check_defaultness(item.span, def); - let msg = "free constant item without body"; - self.error_item_without_body(item.span, "constant", msg, " = ;"); + self.session.emit_err(ConstWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); } ItemKind::Static(.., None) => { - let msg = "free static item without body"; - self.error_item_without_body(item.span, "static", msg, " = ;"); + self.session.emit_err(StaticWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); } ItemKind::TyAlias(box TyAlias { defaultness, @@ -1343,8 +1238,10 @@ fn visit_item(&mut self, item: &'a Item) { }) => { self.check_defaultness(item.span, defaultness); if ty.is_none() { - let msg = "free type alias without body"; - self.error_item_without_body(item.span, "type", msg, " = ;"); + self.session.emit_err(TyAliasWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); } self.check_type_no_bounds(bounds, "this context"); if where_clauses.1.0 { @@ -1648,10 +1545,20 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { if ctxt == AssocCtxt::Impl { match &item.kind { AssocItemKind::Const(_, _, body) => { - self.check_impl_item_provided(item.span, body, "constant", " = ;"); + if body.is_none() { + self.session.emit_err(AssocConstWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); + } } AssocItemKind::Fn(box Fn { body, .. }) => { - self.check_impl_item_provided(item.span, body, "function", " { }"); + if body.is_none() { + self.session.emit_err(AssocFnWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); + } } AssocItemKind::TyAlias(box TyAlias { generics, @@ -1661,7 +1568,12 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { ty, .. }) => { - self.check_impl_item_provided(item.span, ty, "type", " = ;"); + if ty.is_none() { + self.session.emit_err(AssocTypeWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); + } self.check_type_no_bounds(bounds, "`impl`s"); if ty.is_some() { self.check_gat_where( @@ -1876,7 +1788,7 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> /// Used to forbid `let` expressions in certain syntactic locations. #[derive(Clone, Copy)] -enum ForbiddenLetReason { +pub(crate) enum ForbiddenLetReason { /// `let` is not valid and the source environment is not important GenericForbidden, /// A let chain with the `||` operator diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs new file mode 100644 index 00000000000..16ba14e9092 --- /dev/null +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -0,0 +1,248 @@ +//! Errors emitted by ast_passes. + +use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic}; +use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_span::{Span, Symbol}; + +use crate::ast_validation::ForbiddenLetReason; + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_let)] +#[note] +pub struct ForbiddenLet { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub(crate) reason: ForbiddenLetReason, +} + +impl AddSubdiagnostic for ForbiddenLetReason { + fn add_to_diagnostic(self, diag: &mut Diagnostic) { + match self { + Self::GenericForbidden => {} + Self::NotSupportedOr(span) => { + diag.span_note(span, fluent::ast_passes::not_supported_or); + } + Self::NotSupportedParentheses(span) => { + diag.span_note(span, fluent::ast_passes::not_supported_parentheses); + } + } + } +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_assoc_constraint)] +pub struct ForbiddenAssocConstraint { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::keyword_lifetime)] +pub struct KeywordLifetime { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::invalid_label)] +pub struct InvalidLabel { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::invalid_visibility, code = "E0449")] +pub struct InvalidVisibility { + #[primary_span] + pub span: Span, + #[label(ast_passes::implied)] + pub implied: Option, + #[subdiagnostic] + pub note: Option, +} + +#[derive(SessionSubdiagnostic)] +pub enum InvalidVisibilityNote { + #[note(ast_passes::individual_impl_items)] + IndividualImplItems, + #[note(ast_passes::individual_foreign_items)] + IndividualForeignItems, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::trait_fn_async, code = "E0706")] +#[note] +#[note(ast_passes::note2)] +pub struct TraitFnAsync { + #[primary_span] + pub fn_span: Span, + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::trait_fn_const, code = "E0379")] +pub struct TraitFnConst { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_lifetime_bound)] +pub struct ForbiddenLifetimeBound { + #[primary_span] + pub spans: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_non_lifetime_param)] +pub struct ForbiddenNonLifetimeParam { + #[primary_span] + pub spans: Vec, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_too_many)] +pub struct FnParamTooMany { + #[primary_span] + pub span: Span, + pub max_num_args: usize, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_c_var_args_only)] +pub struct FnParamCVarArgsOnly { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_c_var_args_not_last)] +pub struct FnParamCVarArgsNotLast { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_doc_comment)] +pub struct FnParamDocComment { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_forbidden_attr)] +pub struct FnParamForbiddenAttr { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_param_forbidden_self)] +#[note] +pub struct FnParamForbiddenSelf { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::forbidden_default)] +pub struct ForbiddenDefault { + #[primary_span] + pub span: Span, + #[label] + pub def_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::assoc_const_without_body)] +pub struct AssocConstWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " = ;", applicability = "has-placeholders")] + pub replace_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::assoc_fn_without_body)] +pub struct AssocFnWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " {{ }}", applicability = "has-placeholders")] + pub replace_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::assoc_type_without_body)] +pub struct AssocTypeWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " = ;", applicability = "has-placeholders")] + pub replace_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::const_without_body)] +pub struct ConstWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " = ;", applicability = "has-placeholders")] + pub replace_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::static_without_body)] +pub struct StaticWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " = ;", applicability = "has-placeholders")] + pub replace_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::ty_alias_without_body)] +pub struct TyAliasWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " = ;", applicability = "has-placeholders")] + pub replace_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(ast_passes::fn_without_body)] +pub struct FnWithoutBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " {{ }}", applicability = "has-placeholders")] + pub replace_span: Span, + #[subdiagnostic] + pub extern_block_suggestion: Option, +} + +pub struct ExternBlockSuggestion { + pub start_span: Span, + pub end_span: Span, + pub abi: Option, +} + +impl AddSubdiagnostic for ExternBlockSuggestion { + fn add_to_diagnostic(self, diag: &mut Diagnostic) { + let start_suggestion = if let Some(abi) = self.abi { + format!("extern \"{}\" {{", abi) + } else { + "extern {".to_owned() + }; + let end_suggestion = " }".to_owned(); + + diag.multipart_suggestion( + fluent::ast_passes::extern_block_suggestion, + vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)], + Applicability::MaybeIncorrect, + ); + } +} diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 2bc3b6f3616..6a826298985 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -12,6 +12,7 @@ #![recursion_limit = "256"] pub mod ast_validation; +mod errors; pub mod feature_gate; pub mod node_count; pub mod show_span; diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 08026c9d357..fd517c1e121 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -1176,7 +1176,7 @@ fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>) cx.ecx.buffered_early_lint.push(BufferedEarlyLint { span: MultiSpan::from_span(named_arg.positional_named_arg_span), - msg: msg.clone(), + msg: msg.into(), node_id: ast::CRATE_NODE_ID, lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY), diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally { diff --git a/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl b/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl new file mode 100644 index 00000000000..db91a886c72 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl @@ -0,0 +1,93 @@ +ast_passes_forbidden_let = + `let` expressions are not supported here + .note = only supported directly in conditions of `if` and `while` expressions + .not_supported_or = `||` operators are not supported in let chain expressions + .not_supported_parentheses = `let`s wrapped in parentheses are not supported in a context with let chains + +ast_passes_deprecated_where_clause_location = + where clause not allowed here + +ast_passes_forbidden_assoc_constraint = + associated type bounds are not allowed within structs, enums, or unions + +ast_passes_keyword_lifetime = + lifetimes cannot use keyword names + +ast_passes_invalid_label = + invalid label name `{$name}` + +ast_passes_invalid_visibility = + unnecessary visibility qualifier + .implied = `pub` not permitted here because it's implied + .individual_impl_items = place qualifiers on individual impl items instead + .individual_foreign_items = place qualifiers on individual foreign items instead + +ast_passes_trait_fn_async = + functions in traits cannot be declared `async` + .label = `async` because of this + .note = `async` trait functions are not currently supported + .note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait + +ast_passes_trait_fn_const = + functions in traits cannot be declared const + .label = functions in traits cannot be const + +ast_passes_forbidden_lifetime_bound = + lifetime bounds cannot be used in this context + +ast_passes_forbidden_non_lifetime_param = + only lifetime parameters can be used in this context + +ast_passes_fn_param_too_many = + function can not have more than {$max_num_args} arguments + +ast_passes_fn_param_c_var_args_only = + C-variadic function must be declared with at least one named argument + +ast_passes_fn_param_c_var_args_not_last = + `...` must be the last argument of a C-variadic function + +ast_passes_fn_param_doc_comment = + documentation comments cannot be applied to function parameters + .label = doc comments are not allowed here + +ast_passes_fn_param_forbidden_attr = + allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + +ast_passes_fn_param_forbidden_self = + `self` parameter is only allowed in associated functions + .label = not semantically valid as function parameter + .note = associated functions are those in `impl` or `trait` definitions + +ast_passes_forbidden_default = + `default` is only allowed on items in trait impls + .label = `default` because of this + +ast_passes_assoc_const_without_body = + associated constant in `impl` without body + .suggestion = provide a definition for the constant + +ast_passes_assoc_fn_without_body = + associated function in `impl` without body + .suggestion = provide a definition for the function + +ast_passes_assoc_type_without_body = + associated type in `impl` without body + .suggestion = provide a definition for the type + +ast_passes_const_without_body = + free constant item without body + .suggestion = provide a definition for the constant + +ast_passes_static_without_body = + free static item without body + .suggestion = provide a definition for the static + +ast_passes_ty_alias_without_body = + free type alias without body + .suggestion = provide a definition for the type + +ast_passes_fn_without_body = + free function without a body + .suggestion = provide a definition for the function + .extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index ee978f04be2..3569c7f0630 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -32,6 +32,7 @@ // Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module. fluent_messages! { + ast_passes => "../locales/en-US/ast_passes.ftl", borrowck => "../locales/en-US/borrowck.ftl", builtin_macros => "../locales/en-US/builtin_macros.ftl", const_eval => "../locales/en-US/const_eval.ftl", diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 580a4566869..cdb5b3c4284 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -45,7 +45,7 @@ fn check_id(&mut self, id: ast::NodeId) { lint_id.lint, Some(span), |lint| { - lint.build(&msg).emit(); + lint.build(msg).emit(); }, diagnostic, ); diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index a826f599e9c..9e7cbba9511 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -9,7 +9,7 @@ use rustc_ast::node_id::{NodeId, NodeMap}; use rustc_ast::{AttrId, Attribute}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; -use rustc_error_messages::MultiSpan; +use rustc_error_messages::{DiagnosticMessage, MultiSpan}; use rustc_hir::HashStableContext; use rustc_hir::HirId; use rustc_span::edition::Edition; @@ -491,7 +491,7 @@ pub struct BufferedEarlyLint { pub span: MultiSpan, /// The lint message. - pub msg: String, + pub msg: DiagnosticMessage, /// The `NodeId` of the AST node that generated the lint. pub node_id: NodeId, @@ -520,11 +520,11 @@ pub fn add_lint( lint: &'static Lint, node_id: NodeId, span: MultiSpan, - msg: &str, + msg: impl Into, diagnostic: BuiltinLintDiagnostics, ) { let lint_id = LintId::of(lint); - let msg = msg.to_string(); + let msg = msg.into(); self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, msg, diagnostic }); } @@ -537,7 +537,7 @@ pub fn buffer_lint( lint: &'static Lint, id: NodeId, sp: impl Into, - msg: &str, + msg: impl Into, ) { self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiagnostics::Normal) } @@ -547,7 +547,7 @@ pub fn buffer_lint_with_diagnostic( lint: &'static Lint, id: NodeId, sp: impl Into, - msg: &str, + msg: impl Into, diagnostic: BuiltinLintDiagnostics, ) { self.add_lint(lint, id, sp.into(), msg, diagnostic) diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 002abb152f7..ad9ecd39b9e 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -235,35 +235,40 @@ fn build_format(&self, input: &str, span: proc_macro2::Span) -> TokenStream { // the referenced fields. Leaves `it` sitting on the closing brace of the format string, so // the next call to `it.next()` retrieves the next character. while let Some(c) = it.next() { - if c == '{' && *it.peek().unwrap_or(&'\0') != '{' { - let mut eat_argument = || -> Option { - let mut result = String::new(); - // Format specifiers look like: - // - // format := '{' [ argument ] [ ':' format_spec ] '}' . - // - // Therefore, we only need to eat until ':' or '}' to find the argument. - while let Some(c) = it.next() { - result.push(c); - let next = *it.peek().unwrap_or(&'\0'); - if next == '}' { - break; - } else if next == ':' { - // Eat the ':' character. - assert_eq!(it.next().unwrap(), ':'); - break; - } + if c != '{' { + continue; + } + if *it.peek().unwrap_or(&'\0') == '{' { + assert_eq!(it.next().unwrap(), '{'); + continue; + } + let mut eat_argument = || -> Option { + let mut result = String::new(); + // Format specifiers look like: + // + // format := '{' [ argument ] [ ':' format_spec ] '}' . + // + // Therefore, we only need to eat until ':' or '}' to find the argument. + while let Some(c) = it.next() { + result.push(c); + let next = *it.peek().unwrap_or(&'\0'); + if next == '}' { + break; + } else if next == ':' { + // Eat the ':' character. + assert_eq!(it.next().unwrap(), ':'); + break; } - // Eat until (and including) the matching '}' - while it.next()? != '}' { - continue; - } - Some(result) - }; - - if let Some(referenced_field) = eat_argument() { - referenced_fields.insert(referenced_field); } + // Eat until (and including) the matching '}' + while it.next()? != '}' { + continue; + } + Some(result) + }; + + if let Some(referenced_field) = eat_argument() { + referenced_fields.insert(referenced_field); } } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index b9b2356130a..17866dc6bdd 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -360,6 +360,17 @@ pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) { self.create_warning(warning).emit() } + pub fn create_fatal<'a>( + &'a self, + fatal: impl SessionDiagnostic<'a, !>, + ) -> DiagnosticBuilder<'a, !> { + fatal.into_diagnostic(self) + } + + pub fn emit_fatal<'a>(&'a self, fatal: impl SessionDiagnostic<'a, !>) -> ! { + self.create_fatal(fatal).emit() + } + #[rustc_lint_diagnostics] pub fn struct_err( &self, @@ -373,6 +384,11 @@ pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilde self.span_diagnostic.struct_warn(msg) } + #[rustc_lint_diagnostics] + pub fn struct_fatal(&self, msg: impl Into) -> DiagnosticBuilder<'_, !> { + self.span_diagnostic.struct_fatal(msg) + } + #[rustc_lint_diagnostics] pub fn struct_diagnostic( &self, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 80de451276c..4972ae2014d 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -482,6 +482,15 @@ pub fn create_warning<'a>( pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) { self.parse_sess.emit_warning(warning) } + pub fn create_fatal<'a>( + &'a self, + fatal: impl SessionDiagnostic<'a, !>, + ) -> DiagnosticBuilder<'a, !> { + self.parse_sess.create_fatal(fatal) + } + pub fn emit_fatal<'a>(&'a self, fatal: impl SessionDiagnostic<'a, !>) -> ! { + self.parse_sess.emit_fatal(fatal) + } #[inline] pub fn err_count(&self) -> usize { self.diagnostic().err_count()