From ba860344e1656eb577b0e1484cd68b16b7735a59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 1 Jan 2024 23:23:11 +0100 Subject: [PATCH 1/4] Don't synthesize host effect params for trait assoc fns marked const --- compiler/rustc_ast_lowering/src/item.rs | 10 ++++++---- .../effects/trait-fn-const.rs | 13 +++++++++++++ .../effects/trait-fn-const.stderr | 15 +++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 3848f3b7782..3e58570767d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1254,11 +1254,13 @@ impl<'hir> LoweringContext<'_, 'hir> { coroutine_kind: Option, ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header); + // Don't pass along the user-provided constness of trait associated functions; we don't want to + // synthesize a host effect param for them. We reject `const` on them during AST validation. + let constness = if kind == FnDeclKind::Inherent { sig.header.constness } else { Const::No }; let itctx = ImplTraitContext::Universal; - let (generics, decl) = - self.lower_generics(generics, sig.header.constness, id, &itctx, |this| { - this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) - }); + let (generics, decl) = self.lower_generics(generics, constness, id, &itctx, |this| { + this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) + }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs new file mode 100644 index 00000000000..40e8bfdcc17 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs @@ -0,0 +1,13 @@ +// Regression test for issue #113378. +#![feature(const_trait_impl, effects)] + +#[const_trait] +trait Trait { + const fn fun(); //~ ERROR functions in traits cannot be declared const +} + +impl const Trait for () { + const fn fun() {} //~ ERROR functions in traits cannot be declared const +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr new file mode 100644 index 00000000000..09fe580ae5c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr @@ -0,0 +1,15 @@ +error[E0379]: functions in traits cannot be declared const + --> $DIR/trait-fn-const.rs:6:5 + | +LL | const fn fun(); + | ^^^^^ functions in traits cannot be const + +error[E0379]: functions in traits cannot be declared const + --> $DIR/trait-fn-const.rs:10:5 + | +LL | const fn fun() {} + | ^^^^^ functions in traits cannot be const + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0379`. From 8f546aa495dee00326d40fe277ed5fef1f68175e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 2 Jan 2024 01:11:21 +0100 Subject: [PATCH 2/4] Turn a bug!() into a span_delay_bug() No reason why this needs to be a `bug!()`. --- compiler/rustc_hir_analysis/src/collect/generics_of.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 5abc752309a..b44b2eefabb 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -315,7 +315,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { if is_host_effect { if let Some(idx) = host_effect_index { - bug!("parent also has host effect param? index: {idx}, def: {def_id:?}"); + tcx.dcx().span_delayed_bug( + param.span, + format!("parent also has host effect param? index: {idx}, def: {def_id:?}"), + ); } host_effect_index = Some(index as usize); From ae8e401c9f8b51dc8ff3ac5914e0203ea95e26d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 2 Jan 2024 00:26:50 +0100 Subject: [PATCH 3/4] E0379: Make diagnostic more precise --- compiler/rustc_ast_passes/messages.ftl | 10 ++++++++-- compiler/rustc_ast_passes/src/ast_validation.rs | 2 +- compiler/rustc_ast_passes/src/errors.rs | 1 + compiler/rustc_error_codes/src/error_codes/E0379.md | 4 ++++ tests/ui/consts/const-fn-mismatch.rs | 2 +- tests/ui/consts/const-fn-mismatch.stderr | 4 ++-- tests/ui/feature-gates/feature-gate-min_const_fn.rs | 2 +- .../ui/feature-gates/feature-gate-min_const_fn.stderr | 4 ++-- tests/ui/mismatched_types/const-fn-in-trait.stderr | 4 ++-- tests/ui/parser/fn-header-semantic-fail.rs | 4 ++-- tests/ui/parser/fn-header-semantic-fail.stderr | 8 ++++---- .../effects/trait-fn-const.rs | 2 +- .../effects/trait-fn-const.stderr | 4 ++-- 13 files changed, 31 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index b5612c1820d..b7274db029f 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -233,8 +233,14 @@ ast_passes_tilde_const_disallowed = `~const` is not allowed here .item = this item cannot have `~const` trait bounds ast_passes_trait_fn_const = - functions in traits cannot be declared const - .label = functions in traits cannot be const + functions in {$in_impl -> + [true] trait impls + *[false] traits + } cannot be declared const + .label = functions in {$in_impl -> + [true] trait impls + *[false] traits + } cannot be const ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index bc5cf463f12..39ea684087e 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -293,7 +293,7 @@ impl<'a> AstValidator<'a> { fn check_trait_fn_not_const(&self, constness: Const) { if let Const::Yes(span) = constness { - self.dcx().emit_err(errors::TraitFnConst { span }); + self.dcx().emit_err(errors::TraitFnConst { span, in_impl: self.in_trait_impl }); } } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 0cec4374be2..ebaa7ccecc9 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -49,6 +49,7 @@ pub struct TraitFnConst { #[primary_span] #[label] pub span: Span, + pub in_impl: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_error_codes/src/error_codes/E0379.md b/compiler/rustc_error_codes/src/error_codes/E0379.md index ab438e41447..35f546cfdb7 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0379.md +++ b/compiler/rustc_error_codes/src/error_codes/E0379.md @@ -6,6 +6,10 @@ Erroneous code example: trait Foo { const fn bar() -> u32; // error! } + +impl Foo for () { + const fn bar() -> u32 { 0 } // error! +} ``` Trait methods cannot be declared `const` by design. For more information, see diff --git a/tests/ui/consts/const-fn-mismatch.rs b/tests/ui/consts/const-fn-mismatch.rs index 3107b8128e6..b17e4cedd3f 100644 --- a/tests/ui/consts/const-fn-mismatch.rs +++ b/tests/ui/consts/const-fn-mismatch.rs @@ -9,7 +9,7 @@ trait Foo { impl Foo for u32 { const fn f() -> u32 { - //~^ ERROR functions in traits cannot be declared const + //~^ ERROR functions in trait impls cannot be declared const 22 } } diff --git a/tests/ui/consts/const-fn-mismatch.stderr b/tests/ui/consts/const-fn-mismatch.stderr index beaf52c0cfb..7d681c212b9 100644 --- a/tests/ui/consts/const-fn-mismatch.stderr +++ b/tests/ui/consts/const-fn-mismatch.stderr @@ -1,8 +1,8 @@ -error[E0379]: functions in traits cannot be declared const +error[E0379]: functions in trait impls cannot be declared const --> $DIR/const-fn-mismatch.rs:11:5 | LL | const fn f() -> u32 { - | ^^^^^ functions in traits cannot be const + | ^^^^^ functions in trait impls cannot be const error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-min_const_fn.rs b/tests/ui/feature-gates/feature-gate-min_const_fn.rs index 8f9b433009d..3d61a9eb937 100644 --- a/tests/ui/feature-gates/feature-gate-min_const_fn.rs +++ b/tests/ui/feature-gates/feature-gate-min_const_fn.rs @@ -8,7 +8,7 @@ trait Foo { } impl Foo for u32 { - const fn foo() -> u32 { 0 } //~ ERROR functions in traits cannot be declared const + const fn foo() -> u32 { 0 } //~ ERROR functions in trait impls cannot be declared const } trait Bar {} diff --git a/tests/ui/feature-gates/feature-gate-min_const_fn.stderr b/tests/ui/feature-gates/feature-gate-min_const_fn.stderr index d7a58591364..abc9ddabd51 100644 --- a/tests/ui/feature-gates/feature-gate-min_const_fn.stderr +++ b/tests/ui/feature-gates/feature-gate-min_const_fn.stderr @@ -10,11 +10,11 @@ error[E0379]: functions in traits cannot be declared const LL | const fn bar() -> u32 { 0 } | ^^^^^ functions in traits cannot be const -error[E0379]: functions in traits cannot be declared const +error[E0379]: functions in trait impls cannot be declared const --> $DIR/feature-gate-min_const_fn.rs:11:5 | LL | const fn foo() -> u32 { 0 } - | ^^^^^ functions in traits cannot be const + | ^^^^^ functions in trait impls cannot be const error: aborting due to 3 previous errors diff --git a/tests/ui/mismatched_types/const-fn-in-trait.stderr b/tests/ui/mismatched_types/const-fn-in-trait.stderr index 7d1fbe45c53..75122237bf5 100644 --- a/tests/ui/mismatched_types/const-fn-in-trait.stderr +++ b/tests/ui/mismatched_types/const-fn-in-trait.stderr @@ -4,11 +4,11 @@ error[E0379]: functions in traits cannot be declared const LL | const fn g(); | ^^^^^ functions in traits cannot be const -error[E0379]: functions in traits cannot be declared const +error[E0379]: functions in trait impls cannot be declared const --> $DIR/const-fn-in-trait.rs:7:5 | LL | const fn f() -> u32 { 22 } - | ^^^^^ functions in traits cannot be const + | ^^^^^ functions in trait impls cannot be const error: aborting due to 2 previous errors diff --git a/tests/ui/parser/fn-header-semantic-fail.rs b/tests/ui/parser/fn-header-semantic-fail.rs index f8b58cad7c1..f01e1c2277c 100644 --- a/tests/ui/parser/fn-header-semantic-fail.rs +++ b/tests/ui/parser/fn-header-semantic-fail.rs @@ -26,10 +26,10 @@ fn main() { impl X for Y { async fn ft1() {} // OK. unsafe fn ft2() {} // OK. - const fn ft3() {} //~ ERROR functions in traits cannot be declared const + const fn ft3() {} //~ ERROR functions in trait impls cannot be declared const extern "C" fn ft4() {} const async unsafe extern "C" fn ft5() {} - //~^ ERROR functions in traits cannot be declared const + //~^ ERROR functions in trait impls cannot be declared const //~| ERROR functions cannot be both `const` and `async` } diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/fn-header-semantic-fail.stderr index cdf01e0c5df..1f280424cf3 100644 --- a/tests/ui/parser/fn-header-semantic-fail.stderr +++ b/tests/ui/parser/fn-header-semantic-fail.stderr @@ -28,17 +28,17 @@ LL | const async unsafe extern "C" fn ft5(); | | `async` because of this | `const` because of this -error[E0379]: functions in traits cannot be declared const +error[E0379]: functions in trait impls cannot be declared const --> $DIR/fn-header-semantic-fail.rs:29:9 | LL | const fn ft3() {} - | ^^^^^ functions in traits cannot be const + | ^^^^^ functions in trait impls cannot be const -error[E0379]: functions in traits cannot be declared const +error[E0379]: functions in trait impls cannot be declared const --> $DIR/fn-header-semantic-fail.rs:31:9 | LL | const async unsafe extern "C" fn ft5() {} - | ^^^^^ functions in traits cannot be const + | ^^^^^ functions in trait impls cannot be const error: functions cannot be both `const` and `async` --> $DIR/fn-header-semantic-fail.rs:31:9 diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs index 40e8bfdcc17..0d1c926fef5 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs @@ -7,7 +7,7 @@ trait Trait { } impl const Trait for () { - const fn fun() {} //~ ERROR functions in traits cannot be declared const + const fn fun() {} //~ ERROR functions in trait impls cannot be declared const } fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr index 09fe580ae5c..cf8a2772d89 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr @@ -4,11 +4,11 @@ error[E0379]: functions in traits cannot be declared const LL | const fn fun(); | ^^^^^ functions in traits cannot be const -error[E0379]: functions in traits cannot be declared const +error[E0379]: functions in trait impls cannot be declared const --> $DIR/trait-fn-const.rs:10:5 | LL | const fn fun() {} - | ^^^^^ functions in traits cannot be const + | ^^^^^ functions in trait impls cannot be const error: aborting due to 2 previous errors From aa799049d731f2922c237b27211d4e19b4db918b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 2 Jan 2024 00:57:30 +0100 Subject: [PATCH 4/4] E0379: Provide suggestions --- compiler/rustc_ast_passes/messages.ftl | 7 + .../rustc_ast_passes/src/ast_validation.rs | 130 +++++++++++++----- compiler/rustc_ast_passes/src/errors.rs | 19 ++- tests/ui/consts/const-fn-mismatch.stderr | 5 +- tests/ui/consts/const-fn-not-in-trait.stderr | 10 +- tests/ui/consts/issue-54954.stderr | 5 +- .../feature-gate-min_const_fn.stderr | 15 +- .../mismatched_types/const-fn-in-trait.stderr | 10 +- .../ui/parser/fn-header-semantic-fail.stderr | 20 ++- .../effects/trait-fn-const.rs | 10 +- .../effects/trait-fn-const.stderr | 48 ++++++- 11 files changed, 228 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index b7274db029f..feea02c679c 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -241,6 +241,13 @@ ast_passes_trait_fn_const = [true] trait impls *[false] traits } cannot be const + .const_context_label = this declares all associated functions implicitly const + .remove_const_sugg = remove the `const`{$requires_multiple_changes -> + [true] {" ..."} + *[false] {""} + } + .make_impl_const_sugg = ... and declare the impl to be const instead + .make_trait_const_sugg = ... and declare the trait to be a `#[const_trait]` instead ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 39ea684087e..b69d4cccaf0 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -46,6 +46,21 @@ enum DisallowTildeConstContext<'a> { Item, } +enum TraitOrTraitImpl<'a> { + Trait { span: Span, constness: Option }, + TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: &'a TraitRef }, +} + +impl<'a> TraitOrTraitImpl<'a> { + fn constness(&self) -> Option { + match self { + Self::Trait { constness: Some(span), .. } + | Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span), + _ => None, + } + } +} + struct AstValidator<'a> { session: &'a Session, features: &'a Features, @@ -53,11 +68,7 @@ struct AstValidator<'a> { /// The span of the `extern` in an `extern { ... }` block, if any. extern_mod: Option<&'a Item>, - /// Are we inside a trait impl? - in_trait_impl: bool, - - /// Are we inside a const trait defn or impl? - in_const_trait_or_impl: bool, + outer_trait_or_trait_impl: Option>, has_proc_macro_decls: bool, @@ -78,24 +89,28 @@ struct AstValidator<'a> { impl<'a> AstValidator<'a> { fn with_in_trait_impl( &mut self, - is_in: bool, - constness: Option, + trait_: Option<(Const, ImplPolarity, &'a TraitRef)>, f: impl FnOnce(&mut Self), ) { - let old = mem::replace(&mut self.in_trait_impl, is_in); - let old_const = mem::replace( - &mut self.in_const_trait_or_impl, - matches!(constness, Some(Const::Yes(_))), + let old = mem::replace( + &mut self.outer_trait_or_trait_impl, + trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl { + constness, + polarity, + trait_ref, + }), ); f(self); - self.in_trait_impl = old; - self.in_const_trait_or_impl = old_const; + self.outer_trait_or_trait_impl = old; } - fn with_in_trait(&mut self, is_const: bool, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.in_const_trait_or_impl, is_const); + fn with_in_trait(&mut self, span: Span, constness: Option, f: impl FnOnce(&mut Self)) { + let old = mem::replace( + &mut self.outer_trait_or_trait_impl, + Some(TraitOrTraitImpl::Trait { span, constness }), + ); f(self); - self.in_const_trait_or_impl = old; + self.outer_trait_or_trait_impl = old; } fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { @@ -291,10 +306,48 @@ impl<'a> AstValidator<'a> { } } - fn check_trait_fn_not_const(&self, constness: Const) { - if let Const::Yes(span) = constness { - self.dcx().emit_err(errors::TraitFnConst { span, in_impl: self.in_trait_impl }); - } + fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl<'a>) { + let Const::Yes(span) = constness else { + return; + }; + + let make_impl_const_sugg = if self.features.const_trait_impl + && let TraitOrTraitImpl::TraitImpl { + constness: Const::No, + polarity: ImplPolarity::Positive, + trait_ref, + } = parent + { + Some(trait_ref.path.span.shrink_to_lo()) + } else { + None + }; + + let make_trait_const_sugg = if self.features.const_trait_impl + && let TraitOrTraitImpl::Trait { span, constness: None } = parent + { + Some(span.shrink_to_lo()) + } else { + None + }; + + let parent_constness = parent.constness(); + self.dcx().emit_err(errors::TraitFnConst { + span, + in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }), + const_context_label: parent_constness, + remove_const_sugg: ( + self.session.source_map().span_extend_while(span, |c| c == ' ').unwrap_or(span), + match parent_constness { + Some(_) => rustc_errors::Applicability::MachineApplicable, + None => rustc_errors::Applicability::MaybeIncorrect, + }, + ), + requires_multiple_changes: make_impl_const_sugg.is_some() + || make_trait_const_sugg.is_some(), + make_impl_const_sugg, + make_trait_const_sugg, + }); } fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { @@ -817,7 +870,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self_ty, items, }) => { - self.with_in_trait_impl(true, Some(*constness), |this| { + self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| { this.visibility_not_permitted( &item.vis, errors::VisibilityNotPermittedNote::TraitImpl, @@ -963,8 +1016,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => { - let is_const_trait = attr::contains_name(&item.attrs, sym::const_trait); - self.with_in_trait(is_const_trait, |this| { + let is_const_trait = + attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span); + self.with_in_trait(item.span, is_const_trait, |this| { if *is_auto == IsAuto::Yes { // Auto traits cannot have generics, super traits nor contain items. this.deny_generic_params(generics, item.ident.span); @@ -977,8 +1031,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // context for the supertraits. this.visit_vis(&item.vis); this.visit_ident(item.ident); - let disallowed = - (!is_const_trait).then(|| DisallowTildeConstContext::Trait(item.span)); + let disallowed = is_const_trait + .is_none() + .then(|| DisallowTildeConstContext::Trait(item.span)); this.with_tilde_const(disallowed, |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) @@ -1342,7 +1397,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { let tilde_const_allowed = matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. })) - || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)) if self.in_const_trait_or_impl); + || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_))) + && self + .outer_trait_or_trait_impl + .as_ref() + .and_then(TraitOrTraitImpl::constness) + .is_some(); let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk)); self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk)); @@ -1353,7 +1413,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_nomangle_item_asciionly(item.ident, item.span); } - if ctxt == AssocCtxt::Trait || !self.in_trait_impl { + if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() { self.check_defaultness(item.span, item.kind.defaultness()); } @@ -1401,10 +1461,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ); } - if ctxt == AssocCtxt::Trait || self.in_trait_impl { + if let Some(parent) = &self.outer_trait_or_trait_impl { self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl); if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { - self.check_trait_fn_not_const(sig.header.constness); + self.check_trait_fn_not_const(sig.header.constness, parent); } } @@ -1414,7 +1474,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match &item.kind { AssocItemKind::Fn(box Fn { sig, generics, body, .. }) - if self.in_const_trait_or_impl + if self + .outer_trait_or_trait_impl + .as_ref() + .and_then(TraitOrTraitImpl::constness) + .is_some() || ctxt == AssocCtxt::Trait || matches!(sig.header.constness, Const::Yes(_)) => { @@ -1430,8 +1494,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ); self.visit_fn(kind, item.span, item.id); } - _ => self - .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)), + _ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)), } } } @@ -1547,8 +1610,7 @@ pub fn check_crate( session, features, extern_mod: None, - in_trait_impl: false, - in_const_trait_or_impl: false, + outer_trait_or_trait_impl: None, has_proc_macro_decls: false, outer_impl_trait: None, disallow_tilde_const: Some(DisallowTildeConstContext::Item), diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index ebaa7ccecc9..42ada39f515 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -1,7 +1,7 @@ //! Errors emitted by ast_passes. use rustc_ast::ParamKindOrd; -use rustc_errors::AddToDiagnostic; +use rustc_errors::{AddToDiagnostic, Applicability}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -50,6 +50,23 @@ pub struct TraitFnConst { #[label] pub span: Span, pub in_impl: bool, + #[label(ast_passes_const_context_label)] + pub const_context_label: Option, + #[suggestion(ast_passes_remove_const_sugg, code = "")] + pub remove_const_sugg: (Span, Applicability), + pub requires_multiple_changes: bool, + #[suggestion( + ast_passes_make_impl_const_sugg, + code = "const ", + applicability = "maybe-incorrect" + )] + pub make_impl_const_sugg: Option, + #[suggestion( + ast_passes_make_trait_const_sugg, + code = "#[const_trait]\n", + applicability = "maybe-incorrect" + )] + pub make_trait_const_sugg: Option, } #[derive(Diagnostic)] diff --git a/tests/ui/consts/const-fn-mismatch.stderr b/tests/ui/consts/const-fn-mismatch.stderr index 7d681c212b9..9e7d93b0c97 100644 --- a/tests/ui/consts/const-fn-mismatch.stderr +++ b/tests/ui/consts/const-fn-mismatch.stderr @@ -2,7 +2,10 @@ error[E0379]: functions in trait impls cannot be declared const --> $DIR/const-fn-mismatch.rs:11:5 | LL | const fn f() -> u32 { - | ^^^^^ functions in trait impls cannot be const + | ^^^^^- + | | + | functions in trait impls cannot be const + | help: remove the `const` error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-fn-not-in-trait.stderr b/tests/ui/consts/const-fn-not-in-trait.stderr index 5d364eb882d..04430610ad0 100644 --- a/tests/ui/consts/const-fn-not-in-trait.stderr +++ b/tests/ui/consts/const-fn-not-in-trait.stderr @@ -2,13 +2,19 @@ error[E0379]: functions in traits cannot be declared const --> $DIR/const-fn-not-in-trait.rs:5:5 | LL | const fn f() -> u32; - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error[E0379]: functions in traits cannot be declared const --> $DIR/const-fn-not-in-trait.rs:7:5 | LL | const fn g() -> u32 { - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error: aborting due to 2 previous errors diff --git a/tests/ui/consts/issue-54954.stderr b/tests/ui/consts/issue-54954.stderr index b0701bab793..03c47030c0e 100644 --- a/tests/ui/consts/issue-54954.stderr +++ b/tests/ui/consts/issue-54954.stderr @@ -2,7 +2,10 @@ error[E0379]: functions in traits cannot be declared const --> $DIR/issue-54954.rs:5:5 | LL | const fn const_val() -> usize { - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type --> $DIR/issue-54954.rs:1:24 diff --git a/tests/ui/feature-gates/feature-gate-min_const_fn.stderr b/tests/ui/feature-gates/feature-gate-min_const_fn.stderr index abc9ddabd51..0b16f9abb70 100644 --- a/tests/ui/feature-gates/feature-gate-min_const_fn.stderr +++ b/tests/ui/feature-gates/feature-gate-min_const_fn.stderr @@ -2,19 +2,28 @@ error[E0379]: functions in traits cannot be declared const --> $DIR/feature-gate-min_const_fn.rs:6:5 | LL | const fn foo() -> u32; - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error[E0379]: functions in traits cannot be declared const --> $DIR/feature-gate-min_const_fn.rs:7:5 | LL | const fn bar() -> u32 { 0 } - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error[E0379]: functions in trait impls cannot be declared const --> $DIR/feature-gate-min_const_fn.rs:11:5 | LL | const fn foo() -> u32 { 0 } - | ^^^^^ functions in trait impls cannot be const + | ^^^^^- + | | + | functions in trait impls cannot be const + | help: remove the `const` error: aborting due to 3 previous errors diff --git a/tests/ui/mismatched_types/const-fn-in-trait.stderr b/tests/ui/mismatched_types/const-fn-in-trait.stderr index 75122237bf5..06976933b2f 100644 --- a/tests/ui/mismatched_types/const-fn-in-trait.stderr +++ b/tests/ui/mismatched_types/const-fn-in-trait.stderr @@ -2,13 +2,19 @@ error[E0379]: functions in traits cannot be declared const --> $DIR/const-fn-in-trait.rs:3:5 | LL | const fn g(); - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error[E0379]: functions in trait impls cannot be declared const --> $DIR/const-fn-in-trait.rs:7:5 | LL | const fn f() -> u32 { 22 } - | ^^^^^ functions in trait impls cannot be const + | ^^^^^- + | | + | functions in trait impls cannot be const + | help: remove the `const` error: aborting due to 2 previous errors diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/fn-header-semantic-fail.stderr index 1f280424cf3..696d8e01b63 100644 --- a/tests/ui/parser/fn-header-semantic-fail.stderr +++ b/tests/ui/parser/fn-header-semantic-fail.stderr @@ -11,13 +11,19 @@ error[E0379]: functions in traits cannot be declared const --> $DIR/fn-header-semantic-fail.rs:18:9 | LL | const fn ft3(); - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error[E0379]: functions in traits cannot be declared const --> $DIR/fn-header-semantic-fail.rs:20:9 | LL | const async unsafe extern "C" fn ft5(); - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error: functions cannot be both `const` and `async` --> $DIR/fn-header-semantic-fail.rs:20:9 @@ -32,13 +38,19 @@ error[E0379]: functions in trait impls cannot be declared const --> $DIR/fn-header-semantic-fail.rs:29:9 | LL | const fn ft3() {} - | ^^^^^ functions in trait impls cannot be const + | ^^^^^- + | | + | functions in trait impls cannot be const + | help: remove the `const` error[E0379]: functions in trait impls cannot be declared const --> $DIR/fn-header-semantic-fail.rs:31:9 | LL | const async unsafe extern "C" fn ft5() {} - | ^^^^^ functions in trait impls cannot be const + | ^^^^^- + | | + | functions in trait impls cannot be const + | help: remove the `const` error: functions cannot be both `const` and `async` --> $DIR/fn-header-semantic-fail.rs:31:9 diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs index 0d1c926fef5..891e87d3b97 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.rs @@ -7,7 +7,15 @@ trait Trait { } impl const Trait for () { - const fn fun() {} //~ ERROR functions in trait impls cannot be declared const + const fn fun() {} //~ ERROR functions in trait impls cannot be declared const +} + +impl Trait for u32 { + const fn fun() {} //~ ERROR functions in trait impls cannot be declared const +} + +trait NonConst { + const fn fun(); //~ ERROR functions in traits cannot be declared const } fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr index cf8a2772d89..4d0b03046d2 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/trait-fn-const.stderr @@ -1,15 +1,59 @@ error[E0379]: functions in traits cannot be declared const --> $DIR/trait-fn-const.rs:6:5 | +LL | #[const_trait] + | -------------- this declares all associated functions implicitly const +LL | trait Trait { LL | const fn fun(); - | ^^^^^ functions in traits cannot be const + | ^^^^^- + | | + | functions in traits cannot be const + | help: remove the `const` error[E0379]: functions in trait impls cannot be declared const --> $DIR/trait-fn-const.rs:10:5 | +LL | impl const Trait for () { + | ----- this declares all associated functions implicitly const +LL | const fn fun() {} + | ^^^^^- + | | + | functions in trait impls cannot be const + | help: remove the `const` + +error[E0379]: functions in trait impls cannot be declared const + --> $DIR/trait-fn-const.rs:14:5 + | LL | const fn fun() {} | ^^^^^ functions in trait impls cannot be const + | +help: remove the `const` ... + | +LL - const fn fun() {} +LL + fn fun() {} + | +help: ... and declare the impl to be const instead + | +LL | impl const Trait for u32 { + | +++++ -error: aborting due to 2 previous errors +error[E0379]: functions in traits cannot be declared const + --> $DIR/trait-fn-const.rs:18:5 + | +LL | const fn fun(); + | ^^^^^ functions in traits cannot be const + | +help: remove the `const` ... + | +LL - const fn fun(); +LL + fn fun(); + | +help: ... and declare the trait to be a `#[const_trait]` instead + | +LL + #[const_trait] +LL | trait NonConst { + | + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0379`.