Skip to content

Commit 9a4ac5e

Browse files
committed
Make E0379 diagnostic more helpful
1 parent 36aece9 commit 9a4ac5e

File tree

4 files changed

+49
-16
lines changed

4 files changed

+49
-16
lines changed

compiler/rustc_ast_passes/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ ast_passes_trait_fn_const =
241241
[true] trait impls
242242
*[false] traits
243243
} cannot be const
244+
.const_context_label = this declares all functions implicitly const
245+
.remove_const_sugg = remove the `const`
244246
245247
ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted
246248

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ struct AstValidator<'a> {
5757
in_trait_impl: bool,
5858

5959
/// Are we inside a const trait defn or impl?
60-
in_const_trait_or_impl: bool,
60+
// FIXME(fmease): docs, var name
61+
in_const_trait_or_impl: Option<Span>,
6162

6263
has_proc_macro_decls: bool,
6364

@@ -85,14 +86,17 @@ impl<'a> AstValidator<'a> {
8586
let old = mem::replace(&mut self.in_trait_impl, is_in);
8687
let old_const = mem::replace(
8788
&mut self.in_const_trait_or_impl,
88-
matches!(constness, Some(Const::Yes(_))),
89+
match constness {
90+
Some(Const::Yes(span)) => Some(span),
91+
_ => None,
92+
},
8993
);
9094
f(self);
9195
self.in_trait_impl = old;
9296
self.in_const_trait_or_impl = old_const;
9397
}
9498

95-
fn with_in_trait(&mut self, is_const: bool, f: impl FnOnce(&mut Self)) {
99+
fn with_in_trait(&mut self, is_const: Option<Span>, f: impl FnOnce(&mut Self)) {
96100
let old = mem::replace(&mut self.in_const_trait_or_impl, is_const);
97101
f(self);
98102
self.in_const_trait_or_impl = old;
@@ -292,9 +296,18 @@ impl<'a> AstValidator<'a> {
292296
}
293297

294298
fn check_trait_fn_not_const(&self, constness: Const) {
295-
if let Const::Yes(span) = constness {
296-
self.dcx().emit_err(errors::TraitFnConst { span, in_impl: self.in_trait_impl });
297-
}
299+
let Const::Yes(span) = constness else {
300+
return;
301+
};
302+
303+
// FIXME(const_trait_impl): If the trait or impl is not const and feature `const_trait_impl`
304+
// is enabled, provide a structured suggestion to make the trait (impl) const.
305+
self.dcx().emit_err(errors::TraitFnConst {
306+
span,
307+
in_impl: self.in_trait_impl,
308+
const_context_label: self.in_const_trait_or_impl,
309+
remove_const_sugg: self.in_const_trait_or_impl.map(|_| span),
310+
});
298311
}
299312

300313
fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
@@ -963,7 +976,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
963976
}
964977
}
965978
ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => {
966-
let is_const_trait = attr::contains_name(&item.attrs, sym::const_trait);
979+
let is_const_trait =
980+
attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span);
967981
self.with_in_trait(is_const_trait, |this| {
968982
if *is_auto == IsAuto::Yes {
969983
// Auto traits cannot have generics, super traits nor contain items.
@@ -977,8 +991,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
977991
// context for the supertraits.
978992
this.visit_vis(&item.vis);
979993
this.visit_ident(item.ident);
980-
let disallowed =
981-
(!is_const_trait).then(|| DisallowTildeConstContext::Trait(item.span));
994+
let disallowed = is_const_trait
995+
.is_none()
996+
.then(|| DisallowTildeConstContext::Trait(item.span));
982997
this.with_tilde_const(disallowed, |this| {
983998
this.visit_generics(generics);
984999
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
@@ -1340,9 +1355,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13401355
});
13411356
}
13421357

1343-
let tilde_const_allowed =
1344-
matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
1345-
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)) if self.in_const_trait_or_impl);
1358+
let tilde_const_allowed = matches!(
1359+
fk.header(),
1360+
Some(FnHeader { constness: ast::Const::Yes(_), .. })
1361+
) || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)) if self.in_const_trait_or_impl.is_some());
13461362

13471363
let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
13481364
self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
@@ -1414,7 +1430,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14141430

14151431
match &item.kind {
14161432
AssocItemKind::Fn(box Fn { sig, generics, body, .. })
1417-
if self.in_const_trait_or_impl
1433+
if self.in_const_trait_or_impl.is_some()
14181434
|| ctxt == AssocCtxt::Trait
14191435
|| matches!(sig.header.constness, Const::Yes(_)) =>
14201436
{
@@ -1548,7 +1564,7 @@ pub fn check_crate(
15481564
features,
15491565
extern_mod: None,
15501566
in_trait_impl: false,
1551-
in_const_trait_or_impl: false,
1567+
in_const_trait_or_impl: None,
15521568
has_proc_macro_decls: false,
15531569
outer_impl_trait: None,
15541570
disallow_tilde_const: Some(DisallowTildeConstContext::Item),

compiler/rustc_ast_passes/src/errors.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ pub struct TraitFnConst {
5050
#[label]
5151
pub span: Span,
5252
pub in_impl: bool,
53+
#[label(ast_passes_const_context_label)]
54+
pub const_context_label: Option<Span>,
55+
#[suggestion(ast_passes_remove_const_sugg, code = "", applicability = "machine-applicable")]
56+
pub remove_const_sugg: Option<Span>,
5357
}
5458

5559
#[derive(Diagnostic)]

tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
error[E0379]: functions in traits cannot be declared const
22
--> $DIR/trait-fn-const.rs:8:5
33
|
4+
LL | #[const_trait]
5+
| -------------- this declares all functions implicitly const
6+
LL | trait Trait {
47
LL | const fn fun();
5-
| ^^^^^ functions in traits cannot be const
8+
| ^^^^^
9+
| |
10+
| functions in traits cannot be const
11+
| help: remove the `const`
612

713
error[E0379]: functions in trait impls cannot be declared const
814
--> $DIR/trait-fn-const.rs:12:5
915
|
16+
LL | impl const Trait for () {
17+
| ----- this declares all functions implicitly const
1018
LL | const fn fun() {}
11-
| ^^^^^ functions in trait impls cannot be const
19+
| ^^^^^
20+
| |
21+
| functions in trait impls cannot be const
22+
| help: remove the `const`
1223

1324
error: aborting due to 2 previous errors
1425

0 commit comments

Comments
 (0)