Rollup merge of #100694 - finalchild:ast-passes-diag, r=TaKO8Ki
Migrate rustc_ast_passes diagnostics to `SessionDiagnostic` and translatable messages (first part) Doing a full migration of the `rustc_ast_passes` crate. Making a draft here since there's not yet a tracking issue for the migrations going on. `@rustbot` label +A-translation
This commit is contained in:
commit
57e521e0e5
13 changed files with 490 additions and 203 deletions
|
@ -3595,6 +3595,7 @@ dependencies = [
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_macros",
|
||||||
"rustc_parse",
|
"rustc_parse",
|
||||||
"rustc_session",
|
"rustc_session",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
|
|
|
@ -11,6 +11,7 @@ rustc_attr = { path = "../rustc_attr" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
rustc_feature = { path = "../rustc_feature" }
|
rustc_feature = { path = "../rustc_feature" }
|
||||||
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
rustc_parse = { path = "../rustc_parse" }
|
rustc_parse = { path = "../rustc_parse" }
|
||||||
rustc_session = { path = "../rustc_session" }
|
rustc_session = { path = "../rustc_session" }
|
||||||
rustc_span = { path = "../rustc_span" }
|
rustc_span = { path = "../rustc_span" }
|
||||||
|
|
|
@ -13,7 +13,7 @@ use rustc_ast::walk_list;
|
||||||
use rustc_ast::*;
|
use rustc_ast::*;
|
||||||
use rustc_ast_pretty::pprust::{self, State};
|
use rustc_ast_pretty::pprust::{self, State};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
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_parse::validate_attr;
|
||||||
use rustc_session::lint::builtin::{
|
use rustc_session::lint::builtin::{
|
||||||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
|
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||||
|
@ -27,6 +27,8 @@ use rustc_target::spec::abi;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use crate::errors::*;
|
||||||
|
|
||||||
const MORE_EXTERN: &str =
|
const MORE_EXTERN: &str =
|
||||||
"for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
|
"for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
|
||||||
|
|
||||||
|
@ -117,23 +119,7 @@ impl<'a> AstValidator<'a> {
|
||||||
|
|
||||||
/// Emits an error banning the `let` expression provided in the given location.
|
/// Emits an error banning the `let` expression provided in the given location.
|
||||||
fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
|
fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
|
||||||
let err = "`let` expressions are not supported here";
|
self.session.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_gat_where(
|
fn check_gat_where(
|
||||||
|
@ -163,7 +149,7 @@ impl<'a> AstValidator<'a> {
|
||||||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||||
id,
|
id,
|
||||||
where_clauses.0.1,
|
where_clauses.0.1,
|
||||||
"where clause not allowed here",
|
fluent::ast_passes::deprecated_where_clause_location,
|
||||||
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
|
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
|
||||||
where_clauses.1.1.shrink_to_hi(),
|
where_clauses.1.1.shrink_to_hi(),
|
||||||
suggestion,
|
suggestion,
|
||||||
|
@ -193,10 +179,7 @@ impl<'a> AstValidator<'a> {
|
||||||
AssocConstraintKind::Equality { .. } => {}
|
AssocConstraintKind::Equality { .. } => {}
|
||||||
AssocConstraintKind::Bound { .. } => {
|
AssocConstraintKind::Bound { .. } => {
|
||||||
if self.is_assoc_ty_bound_banned {
|
if self.is_assoc_ty_bound_banned {
|
||||||
self.err_handler().span_err(
|
self.session.emit_err(ForbiddenAssocConstraint { span: constraint.span });
|
||||||
constraint.span,
|
|
||||||
"associated type bounds are not allowed within structs, enums, or unions",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,31 +251,26 @@ impl<'a> AstValidator<'a> {
|
||||||
fn check_lifetime(&self, ident: Ident) {
|
fn check_lifetime(&self, ident: Ident) {
|
||||||
let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
|
let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
|
||||||
if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
|
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) {
|
fn check_label(&self, ident: Ident) {
|
||||||
if ident.without_first_quote().is_reserved() {
|
if ident.without_first_quote().is_reserved() {
|
||||||
self.err_handler()
|
self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name });
|
||||||
.span_err(ident.span, &format!("invalid label name `{}`", ident.name));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
|
fn invalid_visibility(&self, vis: &Visibility, note: Option<InvalidVisibilityNote>) {
|
||||||
if let VisibilityKind::Inherited = vis.kind {
|
if let VisibilityKind::Inherited = vis.kind {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut err =
|
self.session.emit_err(InvalidVisibility {
|
||||||
struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
|
span: vis.span,
|
||||||
if vis.kind.is_pub() {
|
implied: if vis.kind.is_pub() { Some(vis.span) } else { None },
|
||||||
err.span_label(vis.span, "`pub` not permitted here because it's implied");
|
note,
|
||||||
}
|
});
|
||||||
if let Some(note) = note {
|
|
||||||
err.note(note);
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
|
fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
|
||||||
|
@ -309,29 +287,13 @@ impl<'a> AstValidator<'a> {
|
||||||
|
|
||||||
fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
|
fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
|
||||||
if let Async::Yes { span, .. } = asyncness {
|
if let Async::Yes { span, .. } = asyncness {
|
||||||
struct_span_err!(
|
self.session.emit_err(TraitFnAsync { fn_span, span });
|
||||||
self.session,
|
|
||||||
fn_span,
|
|
||||||
E0706,
|
|
||||||
"functions in traits cannot be declared `async`"
|
|
||||||
)
|
|
||||||
.span_label(span, "`async` because of this")
|
|
||||||
.note("`async` trait functions are not currently supported")
|
|
||||||
.note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_trait_fn_not_const(&self, constness: Const) {
|
fn check_trait_fn_not_const(&self, constness: Const) {
|
||||||
if let Const::Yes(span) = constness {
|
if let Const::Yes(span) = constness {
|
||||||
struct_span_err!(
|
self.session.emit_err(TraitFnConst { span });
|
||||||
self.session,
|
|
||||||
span,
|
|
||||||
E0379,
|
|
||||||
"functions in traits cannot be declared const"
|
|
||||||
)
|
|
||||||
.span_label(span, "functions in traits cannot be const")
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,8 +306,7 @@ impl<'a> AstValidator<'a> {
|
||||||
GenericParamKind::Lifetime { .. } => {
|
GenericParamKind::Lifetime { .. } => {
|
||||||
if !param.bounds.is_empty() {
|
if !param.bounds.is_empty() {
|
||||||
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
|
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
|
||||||
self.err_handler()
|
self.session.emit_err(ForbiddenLifetimeBound { spans });
|
||||||
.span_err(spans, "lifetime bounds cannot be used in this context");
|
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -353,10 +314,7 @@ impl<'a> AstValidator<'a> {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
if !non_lt_param_spans.is_empty() {
|
if !non_lt_param_spans.is_empty() {
|
||||||
self.err_handler().span_err(
|
self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans });
|
||||||
non_lt_param_spans,
|
|
||||||
"only lifetime parameters can be used in this context",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,10 +331,7 @@ impl<'a> AstValidator<'a> {
|
||||||
let max_num_args: usize = u16::MAX.into();
|
let max_num_args: usize = u16::MAX.into();
|
||||||
if fn_decl.inputs.len() > max_num_args {
|
if fn_decl.inputs.len() > max_num_args {
|
||||||
let Param { span, .. } = fn_decl.inputs[0];
|
let Param { span, .. } = fn_decl.inputs[0];
|
||||||
self.err_handler().span_fatal(
|
self.session.emit_fatal(FnParamTooMany { span, max_num_args });
|
||||||
span,
|
|
||||||
&format!("function can not have more than {} arguments", max_num_args),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,19 +339,13 @@ impl<'a> AstValidator<'a> {
|
||||||
match &*fn_decl.inputs {
|
match &*fn_decl.inputs {
|
||||||
[Param { ty, span, .. }] => {
|
[Param { ty, span, .. }] => {
|
||||||
if let TyKind::CVarArgs = ty.kind {
|
if let TyKind::CVarArgs = ty.kind {
|
||||||
self.err_handler().span_err(
|
self.session.emit_err(FnParamCVarArgsOnly { span: *span });
|
||||||
*span,
|
|
||||||
"C-variadic function must be declared with at least one named argument",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[ps @ .., _] => {
|
[ps @ .., _] => {
|
||||||
for Param { ty, span, .. } in ps {
|
for Param { ty, span, .. } in ps {
|
||||||
if let TyKind::CVarArgs = ty.kind {
|
if let TyKind::CVarArgs = ty.kind {
|
||||||
self.err_handler().span_err(
|
self.session.emit_err(FnParamCVarArgsNotLast { span: *span });
|
||||||
*span,
|
|
||||||
"`...` must be the last argument of a C-variadic function",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -423,19 +372,9 @@ impl<'a> AstValidator<'a> {
|
||||||
})
|
})
|
||||||
.for_each(|attr| {
|
.for_each(|attr| {
|
||||||
if attr.is_doc_comment() {
|
if attr.is_doc_comment() {
|
||||||
self.err_handler()
|
self.session.emit_err(FnParamDocComment { span: attr.span });
|
||||||
.struct_span_err(
|
|
||||||
attr.span,
|
|
||||||
"documentation comments cannot be applied to function parameters",
|
|
||||||
)
|
|
||||||
.span_label(attr.span, "doc comments are not allowed here")
|
|
||||||
.emit();
|
|
||||||
} else {
|
} else {
|
||||||
self.err_handler().span_err(
|
self.session.emit_err(FnParamForbiddenAttr { span: attr.span });
|
||||||
attr.span,
|
|
||||||
"allow, cfg, cfg_attr, deny, expect, \
|
|
||||||
forbid, and warn are the only allowed built-in attributes in function parameters",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -443,14 +382,7 @@ impl<'a> AstValidator<'a> {
|
||||||
fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
|
fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
|
||||||
if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
|
if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
|
||||||
if param.is_self() {
|
if param.is_self() {
|
||||||
self.err_handler()
|
self.session.emit_err(FnParamForbiddenSelf { span: param.span });
|
||||||
.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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -458,47 +390,20 @@ impl<'a> AstValidator<'a> {
|
||||||
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
|
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
|
||||||
if let Defaultness::Default(def_span) = defaultness {
|
if let Defaultness::Default(def_span) = defaultness {
|
||||||
let span = self.session.source_map().guess_head_span(span);
|
let span = self.session.source_map().guess_head_span(span);
|
||||||
self.err_handler()
|
self.session.emit_err(ForbiddenDefault { span, def_span });
|
||||||
.struct_span_err(span, "`default` is only allowed on items in trait impls")
|
|
||||||
.span_label(def_span, "`default` because of this")
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
|
/// If `sp` ends with a semicolon, returns it as a `Span`
|
||||||
self.error_item_without_body_with_help(sp, ctx, msg, sugg, |_| ());
|
/// Otherwise, returns `sp.shrink_to_hi()`
|
||||||
}
|
fn ending_semi_or_hi(&self, sp: Span) -> Span {
|
||||||
|
|
||||||
fn error_item_without_body_with_help(
|
|
||||||
&self,
|
|
||||||
sp: Span,
|
|
||||||
ctx: &str,
|
|
||||||
msg: &str,
|
|
||||||
sugg: &str,
|
|
||||||
help: impl FnOnce(&mut Diagnostic),
|
|
||||||
) {
|
|
||||||
let source_map = self.session.source_map();
|
let source_map = self.session.source_map();
|
||||||
let end = source_map.end_point(sp);
|
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
|
end
|
||||||
} else {
|
} else {
|
||||||
sp.shrink_to_hi()
|
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<T>(&self, sp: Span, body: &Option<T>, 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 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
|
|
||||||
self.invalid_visibility(
|
self.invalid_visibility(
|
||||||
&item.vis,
|
&item.vis,
|
||||||
Some("place qualifiers on individual impl items instead"),
|
Some(InvalidVisibilityNote::IndividualImplItems),
|
||||||
);
|
);
|
||||||
if let Unsafe::Yes(span) = unsafety {
|
if let Unsafe::Yes(span) = unsafety {
|
||||||
error(span, "unsafe").code(error_code!(E0197)).emit();
|
error(span, "unsafe").code(error_code!(E0197)).emit();
|
||||||
|
@ -1191,37 +1096,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
self.check_defaultness(item.span, defaultness);
|
self.check_defaultness(item.span, defaultness);
|
||||||
|
|
||||||
if body.is_none() {
|
if body.is_none() {
|
||||||
let msg = "free function without a body";
|
self.session.emit_err(FnWithoutBody {
|
||||||
let ext = sig.header.ext;
|
span: item.span,
|
||||||
|
replace_span: self.ending_semi_or_hi(item.span),
|
||||||
let f = |e: &mut Diagnostic| {
|
extern_block_suggestion: match sig.header.ext {
|
||||||
if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext
|
Extern::None => None,
|
||||||
{
|
Extern::Implicit(start_span) => Some(ExternBlockSuggestion {
|
||||||
let start_suggestion = if let Extern::Explicit(abi, _) = ext {
|
start_span,
|
||||||
format!("extern \"{}\" {{", abi.symbol_unescaped)
|
end_span: item.span.shrink_to_hi(),
|
||||||
} else {
|
abi: None,
|
||||||
"extern {".to_owned()
|
}),
|
||||||
};
|
Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion {
|
||||||
|
start_span,
|
||||||
let end_suggestion = " }".to_owned();
|
end_span: item.span.shrink_to_hi(),
|
||||||
let end_span = item.span.shrink_to_hi();
|
abi: Some(abi.symbol_unescaped),
|
||||||
|
}),
|
||||||
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,
|
|
||||||
" { <body> }",
|
|
||||||
f,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visit_vis(&item.vis);
|
self.visit_vis(&item.vis);
|
||||||
|
@ -1236,7 +1127,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
let old_item = mem::replace(&mut self.extern_mod, Some(item));
|
let old_item = mem::replace(&mut self.extern_mod, Some(item));
|
||||||
self.invalid_visibility(
|
self.invalid_visibility(
|
||||||
&item.vis,
|
&item.vis,
|
||||||
Some("place qualifiers on individual foreign items instead"),
|
Some(InvalidVisibilityNote::IndividualForeignItems),
|
||||||
);
|
);
|
||||||
if let Unsafe::Yes(span) = unsafety {
|
if let Unsafe::Yes(span) = unsafety {
|
||||||
self.err_handler().span_err(span, "extern block cannot be declared unsafe");
|
self.err_handler().span_err(span, "extern block cannot be declared unsafe");
|
||||||
|
@ -1327,12 +1218,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
}
|
}
|
||||||
ItemKind::Const(def, .., None) => {
|
ItemKind::Const(def, .., None) => {
|
||||||
self.check_defaultness(item.span, def);
|
self.check_defaultness(item.span, def);
|
||||||
let msg = "free constant item without body";
|
self.session.emit_err(ConstWithoutBody {
|
||||||
self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
|
span: item.span,
|
||||||
|
replace_span: self.ending_semi_or_hi(item.span),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
ItemKind::Static(.., None) => {
|
ItemKind::Static(.., None) => {
|
||||||
let msg = "free static item without body";
|
self.session.emit_err(StaticWithoutBody {
|
||||||
self.error_item_without_body(item.span, "static", msg, " = <expr>;");
|
span: item.span,
|
||||||
|
replace_span: self.ending_semi_or_hi(item.span),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
ItemKind::TyAlias(box TyAlias {
|
ItemKind::TyAlias(box TyAlias {
|
||||||
defaultness,
|
defaultness,
|
||||||
|
@ -1343,8 +1238,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
}) => {
|
}) => {
|
||||||
self.check_defaultness(item.span, defaultness);
|
self.check_defaultness(item.span, defaultness);
|
||||||
if ty.is_none() {
|
if ty.is_none() {
|
||||||
let msg = "free type alias without body";
|
self.session.emit_err(TyAliasWithoutBody {
|
||||||
self.error_item_without_body(item.span, "type", msg, " = <type>;");
|
span: item.span,
|
||||||
|
replace_span: self.ending_semi_or_hi(item.span),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
self.check_type_no_bounds(bounds, "this context");
|
self.check_type_no_bounds(bounds, "this context");
|
||||||
if where_clauses.1.0 {
|
if where_clauses.1.0 {
|
||||||
|
@ -1648,10 +1545,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
if ctxt == AssocCtxt::Impl {
|
if ctxt == AssocCtxt::Impl {
|
||||||
match &item.kind {
|
match &item.kind {
|
||||||
AssocItemKind::Const(_, _, body) => {
|
AssocItemKind::Const(_, _, body) => {
|
||||||
self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
|
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, .. }) => {
|
AssocItemKind::Fn(box Fn { body, .. }) => {
|
||||||
self.check_impl_item_provided(item.span, body, "function", " { <body> }");
|
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 {
|
AssocItemKind::TyAlias(box TyAlias {
|
||||||
generics,
|
generics,
|
||||||
|
@ -1661,7 +1568,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
ty,
|
ty,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
self.check_impl_item_provided(item.span, ty, "type", " = <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");
|
self.check_type_no_bounds(bounds, "`impl`s");
|
||||||
if ty.is_some() {
|
if ty.is_some() {
|
||||||
self.check_gat_where(
|
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.
|
/// Used to forbid `let` expressions in certain syntactic locations.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
enum ForbiddenLetReason {
|
pub(crate) enum ForbiddenLetReason {
|
||||||
/// `let` is not valid and the source environment is not important
|
/// `let` is not valid and the source environment is not important
|
||||||
GenericForbidden,
|
GenericForbidden,
|
||||||
/// A let chain with the `||` operator
|
/// A let chain with the `||` operator
|
||||||
|
|
248
compiler/rustc_ast_passes/src/errors.rs
Normal file
248
compiler/rustc_ast_passes/src/errors.rs
Normal file
|
@ -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<Span>,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub note: Option<InvalidVisibilityNote>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[diag(ast_passes::forbidden_non_lifetime_param)]
|
||||||
|
pub struct ForbiddenNonLifetimeParam {
|
||||||
|
#[primary_span]
|
||||||
|
pub spans: Vec<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 = " = <expr>;", 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 = " {{ <body> }}", 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 = " = <type>;", 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 = " = <expr>;", 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 = " = <expr>;", 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 = " = <type>;", 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 = " {{ <body> }}", applicability = "has-placeholders")]
|
||||||
|
pub replace_span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub extern_block_suggestion: Option<ExternBlockSuggestion>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ExternBlockSuggestion {
|
||||||
|
pub start_span: Span,
|
||||||
|
pub end_span: Span,
|
||||||
|
pub abi: Option<Symbol>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,7 @@
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
pub mod ast_validation;
|
pub mod ast_validation;
|
||||||
|
mod errors;
|
||||||
pub mod feature_gate;
|
pub mod feature_gate;
|
||||||
pub mod node_count;
|
pub mod node_count;
|
||||||
pub mod show_span;
|
pub mod show_span;
|
||||||
|
|
|
@ -1176,7 +1176,7 @@ fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>)
|
||||||
|
|
||||||
cx.ecx.buffered_early_lint.push(BufferedEarlyLint {
|
cx.ecx.buffered_early_lint.push(BufferedEarlyLint {
|
||||||
span: MultiSpan::from_span(named_arg.positional_named_arg_span),
|
span: MultiSpan::from_span(named_arg.positional_named_arg_span),
|
||||||
msg: msg.clone(),
|
msg: msg.into(),
|
||||||
node_id: ast::CRATE_NODE_ID,
|
node_id: ast::CRATE_NODE_ID,
|
||||||
lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
|
lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
|
||||||
diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
|
diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
|
||||||
|
|
93
compiler/rustc_error_messages/locales/en-US/ast_passes.ftl
Normal file
93
compiler/rustc_error_messages/locales/en-US/ast_passes.ftl
Normal file
|
@ -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
|
|
@ -32,6 +32,7 @@ pub use unic_langid::{langid, LanguageIdentifier};
|
||||||
|
|
||||||
// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
|
// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
|
||||||
fluent_messages! {
|
fluent_messages! {
|
||||||
|
ast_passes => "../locales/en-US/ast_passes.ftl",
|
||||||
borrowck => "../locales/en-US/borrowck.ftl",
|
borrowck => "../locales/en-US/borrowck.ftl",
|
||||||
builtin_macros => "../locales/en-US/builtin_macros.ftl",
|
builtin_macros => "../locales/en-US/builtin_macros.ftl",
|
||||||
const_eval => "../locales/en-US/const_eval.ftl",
|
const_eval => "../locales/en-US/const_eval.ftl",
|
||||||
|
|
|
@ -45,7 +45,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
|
||||||
lint_id.lint,
|
lint_id.lint,
|
||||||
Some(span),
|
Some(span),
|
||||||
|lint| {
|
|lint| {
|
||||||
lint.build(&msg).emit();
|
lint.build(msg).emit();
|
||||||
},
|
},
|
||||||
diagnostic,
|
diagnostic,
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,7 +9,7 @@ pub use self::Level::*;
|
||||||
use rustc_ast::node_id::{NodeId, NodeMap};
|
use rustc_ast::node_id::{NodeId, NodeMap};
|
||||||
use rustc_ast::{AttrId, Attribute};
|
use rustc_ast::{AttrId, Attribute};
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
|
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::HashStableContext;
|
||||||
use rustc_hir::HirId;
|
use rustc_hir::HirId;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
|
@ -491,7 +491,7 @@ pub struct BufferedEarlyLint {
|
||||||
pub span: MultiSpan,
|
pub span: MultiSpan,
|
||||||
|
|
||||||
/// The lint message.
|
/// The lint message.
|
||||||
pub msg: String,
|
pub msg: DiagnosticMessage,
|
||||||
|
|
||||||
/// The `NodeId` of the AST node that generated the lint.
|
/// The `NodeId` of the AST node that generated the lint.
|
||||||
pub node_id: NodeId,
|
pub node_id: NodeId,
|
||||||
|
@ -520,11 +520,11 @@ impl LintBuffer {
|
||||||
lint: &'static Lint,
|
lint: &'static Lint,
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
span: MultiSpan,
|
span: MultiSpan,
|
||||||
msg: &str,
|
msg: impl Into<DiagnosticMessage>,
|
||||||
diagnostic: BuiltinLintDiagnostics,
|
diagnostic: BuiltinLintDiagnostics,
|
||||||
) {
|
) {
|
||||||
let lint_id = LintId::of(lint);
|
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 });
|
self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, msg, diagnostic });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,7 +537,7 @@ impl LintBuffer {
|
||||||
lint: &'static Lint,
|
lint: &'static Lint,
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
sp: impl Into<MultiSpan>,
|
sp: impl Into<MultiSpan>,
|
||||||
msg: &str,
|
msg: impl Into<DiagnosticMessage>,
|
||||||
) {
|
) {
|
||||||
self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiagnostics::Normal)
|
self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiagnostics::Normal)
|
||||||
}
|
}
|
||||||
|
@ -547,7 +547,7 @@ impl LintBuffer {
|
||||||
lint: &'static Lint,
|
lint: &'static Lint,
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
sp: impl Into<MultiSpan>,
|
sp: impl Into<MultiSpan>,
|
||||||
msg: &str,
|
msg: impl Into<DiagnosticMessage>,
|
||||||
diagnostic: BuiltinLintDiagnostics,
|
diagnostic: BuiltinLintDiagnostics,
|
||||||
) {
|
) {
|
||||||
self.add_lint(lint, id, sp.into(), msg, diagnostic)
|
self.add_lint(lint, id, sp.into(), msg, diagnostic)
|
||||||
|
|
|
@ -235,35 +235,40 @@ pub(crate) trait HasFieldMap {
|
||||||
// the referenced fields. Leaves `it` sitting on the closing brace of the format string, so
|
// 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.
|
// the next call to `it.next()` retrieves the next character.
|
||||||
while let Some(c) = it.next() {
|
while let Some(c) = it.next() {
|
||||||
if c == '{' && *it.peek().unwrap_or(&'\0') != '{' {
|
if c != '{' {
|
||||||
let mut eat_argument = || -> Option<String> {
|
continue;
|
||||||
let mut result = String::new();
|
}
|
||||||
// Format specifiers look like:
|
if *it.peek().unwrap_or(&'\0') == '{' {
|
||||||
//
|
assert_eq!(it.next().unwrap(), '{');
|
||||||
// format := '{' [ argument ] [ ':' format_spec ] '}' .
|
continue;
|
||||||
//
|
}
|
||||||
// Therefore, we only need to eat until ':' or '}' to find the argument.
|
let mut eat_argument = || -> Option<String> {
|
||||||
while let Some(c) = it.next() {
|
let mut result = String::new();
|
||||||
result.push(c);
|
// Format specifiers look like:
|
||||||
let next = *it.peek().unwrap_or(&'\0');
|
//
|
||||||
if next == '}' {
|
// format := '{' [ argument ] [ ':' format_spec ] '}' .
|
||||||
break;
|
//
|
||||||
} else if next == ':' {
|
// Therefore, we only need to eat until ':' or '}' to find the argument.
|
||||||
// Eat the ':' character.
|
while let Some(c) = it.next() {
|
||||||
assert_eq!(it.next().unwrap(), ':');
|
result.push(c);
|
||||||
break;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -360,6 +360,17 @@ impl ParseSess {
|
||||||
self.create_warning(warning).emit()
|
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]
|
#[rustc_lint_diagnostics]
|
||||||
pub fn struct_err(
|
pub fn struct_err(
|
||||||
&self,
|
&self,
|
||||||
|
@ -373,6 +384,11 @@ impl ParseSess {
|
||||||
self.span_diagnostic.struct_warn(msg)
|
self.span_diagnostic.struct_warn(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rustc_lint_diagnostics]
|
||||||
|
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
|
||||||
|
self.span_diagnostic.struct_fatal(msg)
|
||||||
|
}
|
||||||
|
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
pub fn struct_diagnostic<G: EmissionGuarantee>(
|
pub fn struct_diagnostic<G: EmissionGuarantee>(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -482,6 +482,15 @@ impl Session {
|
||||||
pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) {
|
pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) {
|
||||||
self.parse_sess.emit_warning(warning)
|
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]
|
#[inline]
|
||||||
pub fn err_count(&self) -> usize {
|
pub fn err_count(&self) -> usize {
|
||||||
self.diagnostic().err_count()
|
self.diagnostic().err_count()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue