Skip to content

Commit e331ae5

Browse files
committed
Migrate forbidden_default and *_without_body
1 parent 8ed8aac commit e331ae5

File tree

3 files changed

+185
-76
lines changed

3 files changed

+185
-76
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 54 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_ast::walk_list;
1313
use rustc_ast::*;
1414
use rustc_ast_pretty::pprust::{self, State};
1515
use rustc_data_structures::fx::FxHashMap;
16-
use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability, Diagnostic};
16+
use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability};
1717
use rustc_parse::validate_attr;
1818
use rustc_session::lint::builtin::{
1919
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
@@ -390,47 +390,20 @@ impl<'a> AstValidator<'a> {
390390
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
391391
if let Defaultness::Default(def_span) = defaultness {
392392
let span = self.session.source_map().guess_head_span(span);
393-
self.err_handler()
394-
.struct_span_err(span, "`default` is only allowed on items in trait impls")
395-
.span_label(def_span, "`default` because of this")
396-
.emit();
393+
self.session.emit_err(ForbiddenDefault { span, def_span });
397394
}
398395
}
399396

400-
fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
401-
self.error_item_without_body_with_help(sp, ctx, msg, sugg, |_| ());
402-
}
403-
404-
fn error_item_without_body_with_help(
405-
&self,
406-
sp: Span,
407-
ctx: &str,
408-
msg: &str,
409-
sugg: &str,
410-
help: impl FnOnce(&mut Diagnostic),
411-
) {
397+
/// If `sp` ends with a semicolon, returns it as a `Span`
398+
/// Otherwise, returns `sp.shrink_to_hi()`
399+
fn ending_semi_or_hi(&self, sp: Span) -> Span {
412400
let source_map = self.session.source_map();
413401
let end = source_map.end_point(sp);
414-
let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
402+
403+
if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
415404
end
416405
} else {
417406
sp.shrink_to_hi()
418-
};
419-
let mut err = self.err_handler().struct_span_err(sp, msg);
420-
err.span_suggestion(
421-
replace_span,
422-
&format!("provide a definition for the {}", ctx),
423-
sugg,
424-
Applicability::HasPlaceholders,
425-
);
426-
help(&mut err);
427-
err.emit();
428-
}
429-
430-
fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
431-
if body.is_none() {
432-
let msg = format!("associated {} in `impl` without body", ctx);
433-
self.error_item_without_body(sp, ctx, &msg, sugg);
434407
}
435408
}
436409

@@ -1123,37 +1096,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11231096
self.check_defaultness(item.span, defaultness);
11241097

11251098
if body.is_none() {
1126-
let msg = "free function without a body";
1127-
let ext = sig.header.ext;
1128-
1129-
let f = |e: &mut Diagnostic| {
1130-
if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext
1131-
{
1132-
let start_suggestion = if let Extern::Explicit(abi, _) = ext {
1133-
format!("extern \"{}\" {{", abi.symbol_unescaped)
1134-
} else {
1135-
"extern {".to_owned()
1136-
};
1137-
1138-
let end_suggestion = " }".to_owned();
1139-
let end_span = item.span.shrink_to_hi();
1140-
1141-
e
1142-
.multipart_suggestion(
1143-
"if you meant to declare an externally defined function, use an `extern` block",
1144-
vec![(*start_span, start_suggestion), (end_span, end_suggestion)],
1145-
Applicability::MaybeIncorrect,
1146-
);
1147-
}
1148-
};
1149-
1150-
self.error_item_without_body_with_help(
1151-
item.span,
1152-
"function",
1153-
msg,
1154-
" { <body> }",
1155-
f,
1156-
);
1099+
self.session.emit_err(FnWithoutBody {
1100+
span: item.span,
1101+
replace_span: self.ending_semi_or_hi(item.span),
1102+
extern_block_suggestion: match sig.header.ext {
1103+
Extern::None => None,
1104+
Extern::Implicit(start_span) => Some(ExternBlockSuggestion {
1105+
start_span,
1106+
end_span: item.span.shrink_to_hi(),
1107+
abi: None,
1108+
}),
1109+
Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion {
1110+
start_span,
1111+
end_span: item.span.shrink_to_hi(),
1112+
abi: Some(abi.symbol_unescaped),
1113+
}),
1114+
},
1115+
});
11571116
}
11581117

11591118
self.visit_vis(&item.vis);
@@ -1259,12 +1218,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12591218
}
12601219
ItemKind::Const(def, .., None) => {
12611220
self.check_defaultness(item.span, def);
1262-
let msg = "free constant item without body";
1263-
self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1221+
self.session.emit_err(ConstWithoutBody {
1222+
span: item.span,
1223+
replace_span: self.ending_semi_or_hi(item.span),
1224+
});
12641225
}
12651226
ItemKind::Static(.., None) => {
1266-
let msg = "free static item without body";
1267-
self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1227+
self.session.emit_err(StaticWithoutBody {
1228+
span: item.span,
1229+
replace_span: self.ending_semi_or_hi(item.span),
1230+
});
12681231
}
12691232
ItemKind::TyAlias(box TyAlias {
12701233
defaultness,
@@ -1275,8 +1238,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12751238
}) => {
12761239
self.check_defaultness(item.span, defaultness);
12771240
if ty.is_none() {
1278-
let msg = "free type alias without body";
1279-
self.error_item_without_body(item.span, "type", msg, " = <type>;");
1241+
self.session.emit_err(TyAliasWithoutBody {
1242+
span: item.span,
1243+
replace_span: self.ending_semi_or_hi(item.span),
1244+
});
12801245
}
12811246
self.check_type_no_bounds(bounds, "this context");
12821247
if where_clauses.1.0 {
@@ -1580,10 +1545,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
15801545
if ctxt == AssocCtxt::Impl {
15811546
match &item.kind {
15821547
AssocItemKind::Const(_, _, body) => {
1583-
self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1548+
if body.is_none() {
1549+
self.session.emit_err(AssocConstWithoutBody {
1550+
span: item.span,
1551+
replace_span: self.ending_semi_or_hi(item.span),
1552+
});
1553+
}
15841554
}
15851555
AssocItemKind::Fn(box Fn { body, .. }) => {
1586-
self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1556+
if body.is_none() {
1557+
self.session.emit_err(AssocFnWithoutBody {
1558+
span: item.span,
1559+
replace_span: self.ending_semi_or_hi(item.span),
1560+
});
1561+
}
15871562
}
15881563
AssocItemKind::TyAlias(box TyAlias {
15891564
generics,
@@ -1593,7 +1568,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
15931568
ty,
15941569
..
15951570
}) => {
1596-
self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
1571+
if ty.is_none() {
1572+
self.session.emit_err(AssocTypeWithoutBody {
1573+
span: item.span,
1574+
replace_span: self.ending_semi_or_hi(item.span),
1575+
});
1576+
}
15971577
self.check_type_no_bounds(bounds, "`impl`s");
15981578
if ty.is_some() {
15991579
self.check_gat_where(

compiler/rustc_ast_passes/src/errors.rs

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! Errors emitted by ast_passes.
22
3-
use rustc_errors::fluent;
4-
use rustc_errors::{AddSubdiagnostic, Diagnostic};
3+
use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic};
54
use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
65
use rustc_span::{Span, Symbol};
76

@@ -150,3 +149,100 @@ pub struct FnParamForbiddenSelf {
150149
#[label]
151150
pub span: Span,
152151
}
152+
153+
#[derive(SessionDiagnostic)]
154+
#[error(ast_passes::forbidden_default)]
155+
pub struct ForbiddenDefault {
156+
#[primary_span]
157+
pub span: Span,
158+
#[label]
159+
pub def_span: Span,
160+
}
161+
162+
#[derive(SessionDiagnostic)]
163+
#[error(ast_passes::assoc_const_without_body)]
164+
pub struct AssocConstWithoutBody {
165+
#[primary_span]
166+
pub span: Span,
167+
#[suggestion(code = " = <expr>;", applicability = "has-placeholders")]
168+
pub replace_span: Span,
169+
}
170+
171+
#[derive(SessionDiagnostic)]
172+
#[error(ast_passes::assoc_fn_without_body)]
173+
pub struct AssocFnWithoutBody {
174+
#[primary_span]
175+
pub span: Span,
176+
#[suggestion(code = " {{ <body> }}", applicability = "has-placeholders")]
177+
pub replace_span: Span,
178+
}
179+
180+
#[derive(SessionDiagnostic)]
181+
#[error(ast_passes::assoc_type_without_body)]
182+
pub struct AssocTypeWithoutBody {
183+
#[primary_span]
184+
pub span: Span,
185+
#[suggestion(code = " = <type>;", applicability = "has-placeholders")]
186+
pub replace_span: Span,
187+
}
188+
189+
#[derive(SessionDiagnostic)]
190+
#[error(ast_passes::const_without_body)]
191+
pub struct ConstWithoutBody {
192+
#[primary_span]
193+
pub span: Span,
194+
#[suggestion(code = " = <expr>;", applicability = "has-placeholders")]
195+
pub replace_span: Span,
196+
}
197+
198+
#[derive(SessionDiagnostic)]
199+
#[error(ast_passes::static_without_body)]
200+
pub struct StaticWithoutBody {
201+
#[primary_span]
202+
pub span: Span,
203+
#[suggestion(code = " = <expr>;", applicability = "has-placeholders")]
204+
pub replace_span: Span,
205+
}
206+
207+
#[derive(SessionDiagnostic)]
208+
#[error(ast_passes::ty_alias_without_body)]
209+
pub struct TyAliasWithoutBody {
210+
#[primary_span]
211+
pub span: Span,
212+
#[suggestion(code = " = <type>;", applicability = "has-placeholders")]
213+
pub replace_span: Span,
214+
}
215+
216+
#[derive(SessionDiagnostic)]
217+
#[error(ast_passes::fn_without_body)]
218+
pub struct FnWithoutBody {
219+
#[primary_span]
220+
pub span: Span,
221+
#[suggestion(code = " {{ <body> }}", applicability = "has-placeholders")]
222+
pub replace_span: Span,
223+
#[subdiagnostic]
224+
pub extern_block_suggestion: Option<ExternBlockSuggestion>,
225+
}
226+
227+
pub struct ExternBlockSuggestion {
228+
pub start_span: Span,
229+
pub end_span: Span,
230+
pub abi: Option<Symbol>,
231+
}
232+
233+
impl AddSubdiagnostic for ExternBlockSuggestion {
234+
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
235+
let start_suggestion = if let Some(abi) = self.abi {
236+
format!("extern \"{}\" {{", abi)
237+
} else {
238+
"extern {".to_owned()
239+
};
240+
let end_suggestion = " }".to_owned();
241+
242+
diag.multipart_suggestion(
243+
fluent::ast_passes::extern_block_suggestion,
244+
vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)],
245+
Applicability::MaybeIncorrect,
246+
);
247+
}
248+
}

compiler/rustc_error_messages/locales/en-US/ast_passes.ftl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,36 @@ ast_passes_fn_param_forbidden_self =
5858
`self` parameter is only allowed in associated functions
5959
.label = not semantically valid as function parameter
6060
.note = associated functions are those in `impl` or `trait` definitions
61+
62+
ast_passes_forbidden_default =
63+
`default` is only allowed on items in trait impls
64+
.label = `default` because of this
65+
66+
ast_passes_assoc_const_without_body =
67+
associated constant in `impl` without body
68+
.suggestion = provide a definition for the constant
69+
70+
ast_passes_assoc_fn_without_body =
71+
associated function in `impl` without body
72+
.suggestion = provide a definition for the function
73+
74+
ast_passes_assoc_type_without_body =
75+
associated type in `impl` without body
76+
.suggestion = provide a definition for the type
77+
78+
ast_passes_const_without_body =
79+
free constant item without body
80+
.suggestion = provide a definition for the constant
81+
82+
ast_passes_static_without_body =
83+
free static item without body
84+
.suggestion = provide a definition for the static
85+
86+
ast_passes_ty_alias_without_body =
87+
free type alias without body
88+
.suggestion = provide a definition for the type
89+
90+
ast_passes_fn_without_body =
91+
free function without a body
92+
.suggestion = provide a definition for the function
93+
.extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block

0 commit comments

Comments
 (0)