Skip to content

Commit 0e333c6

Browse files
committed
Make E0379 diagnostic more helpful
1 parent 36aece9 commit 0e333c6

File tree

4 files changed

+50
-16
lines changed

4 files changed

+50
-16
lines changed

compiler/rustc_ast_passes/messages.ftl

+2
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

+31-14
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ 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+
///
61+
/// If so, this is the span of the constness.
62+
in_const_trait_or_impl: Option<Span>,
6163

6264
has_proc_macro_decls: bool,
6365

@@ -85,14 +87,17 @@ impl<'a> AstValidator<'a> {
8587
let old = mem::replace(&mut self.in_trait_impl, is_in);
8688
let old_const = mem::replace(
8789
&mut self.in_const_trait_or_impl,
88-
matches!(constness, Some(Const::Yes(_))),
90+
match constness {
91+
Some(Const::Yes(span)) => Some(span),
92+
_ => None,
93+
},
8994
);
9095
f(self);
9196
self.in_trait_impl = old;
9297
self.in_const_trait_or_impl = old_const;
9398
}
9499

95-
fn with_in_trait(&mut self, is_const: bool, f: impl FnOnce(&mut Self)) {
100+
fn with_in_trait(&mut self, is_const: Option<Span>, f: impl FnOnce(&mut Self)) {
96101
let old = mem::replace(&mut self.in_const_trait_or_impl, is_const);
97102
f(self);
98103
self.in_const_trait_or_impl = old;
@@ -292,9 +297,18 @@ impl<'a> AstValidator<'a> {
292297
}
293298

294299
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-
}
300+
let Const::Yes(span) = constness else {
301+
return;
302+
};
303+
304+
// FIXME(const_trait_impl): If the trait or impl is not const and feature `const_trait_impl`
305+
// is enabled, provide a structured suggestion to make the trait (impl) const.
306+
self.dcx().emit_err(errors::TraitFnConst {
307+
span,
308+
in_impl: self.in_trait_impl,
309+
const_context_label: self.in_const_trait_or_impl,
310+
remove_const_sugg: self.in_const_trait_or_impl.map(|_| span),
311+
});
298312
}
299313

300314
fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
@@ -963,7 +977,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
963977
}
964978
}
965979
ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => {
966-
let is_const_trait = attr::contains_name(&item.attrs, sym::const_trait);
980+
let is_const_trait =
981+
attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span);
967982
self.with_in_trait(is_const_trait, |this| {
968983
if *is_auto == IsAuto::Yes {
969984
// Auto traits cannot have generics, super traits nor contain items.
@@ -977,8 +992,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
977992
// context for the supertraits.
978993
this.visit_vis(&item.vis);
979994
this.visit_ident(item.ident);
980-
let disallowed =
981-
(!is_const_trait).then(|| DisallowTildeConstContext::Trait(item.span));
995+
let disallowed = is_const_trait
996+
.is_none()
997+
.then(|| DisallowTildeConstContext::Trait(item.span));
982998
this.with_tilde_const(disallowed, |this| {
983999
this.visit_generics(generics);
9841000
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
@@ -1340,9 +1356,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13401356
});
13411357
}
13421358

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);
1359+
let tilde_const_allowed = matches!(
1360+
fk.header(),
1361+
Some(FnHeader { constness: ast::Const::Yes(_), .. })
1362+
) || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)) if self.in_const_trait_or_impl.is_some());
13461363

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

14151432
match &item.kind {
14161433
AssocItemKind::Fn(box Fn { sig, generics, body, .. })
1417-
if self.in_const_trait_or_impl
1434+
if self.in_const_trait_or_impl.is_some()
14181435
|| ctxt == AssocCtxt::Trait
14191436
|| matches!(sig.header.constness, Const::Yes(_)) =>
14201437
{
@@ -1548,7 +1565,7 @@ pub fn check_crate(
15481565
features,
15491566
extern_mod: None,
15501567
in_trait_impl: false,
1551-
in_const_trait_or_impl: false,
1568+
in_const_trait_or_impl: None,
15521569
has_proc_macro_decls: false,
15531570
outer_impl_trait: None,
15541571
disallow_tilde_const: Some(DisallowTildeConstContext::Item),

compiler/rustc_ast_passes/src/errors.rs

+4
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

+13-2
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)