From 7077797f520b3a588b05d2aa99a2f41c3814e8c3 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Wed, 28 Jan 2026 21:19:09 +0800 Subject: [PATCH] Parse and lower final for methods Co-authored-by: Michael Goulet --- compiler/rustc_ast/src/ast.rs | 12 +++++-- compiler/rustc_ast_lowering/src/item.rs | 21 ++++++----- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + .../rustc_ast_pretty/src/pprust/state/item.rs | 4 +-- .../src/alloc_error_handler.rs | 2 +- compiler/rustc_builtin_macros/src/autodiff.rs | 2 +- .../src/deriving/coerce_pointee.rs | 4 +-- .../src/deriving/generic/mod.rs | 6 ++-- .../src/global_allocator.rs | 2 +- compiler/rustc_builtin_macros/src/test.rs | 2 +- .../rustc_builtin_macros/src/test_harness.rs | 2 +- compiler/rustc_expand/src/build.rs | 2 +- compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_parse/src/errors.rs | 11 ++++++ compiler/rustc_parse/src/parser/item.rs | 35 +++++++++++++------ compiler/rustc_parse/src/parser/token_type.rs | 4 +++ compiler/rustc_span/src/symbol.rs | 1 + tests/ui/coroutine/gen_fn.none.stderr | 4 +-- tests/ui/coroutine/gen_fn.rs | 2 +- ...feature-gate-final-associated-functions.rs | 6 ++++ ...ure-gate-final-associated-functions.stderr | 13 +++++++ tests/ui/parser/duplicate-visibility.rs | 4 +-- tests/ui/parser/duplicate-visibility.stderr | 4 +-- .../parser/misspelled-keywords/pub-fn.stderr | 4 +-- tests/ui/traits/final/final-kw.gated.stderr | 13 +++++++ tests/ui/traits/final/final-kw.rs | 9 +++++ tests/ui/traits/final/final-kw.ungated.stderr | 13 +++++++ 27 files changed, 142 insertions(+), 43 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-final-associated-functions.rs create mode 100644 tests/ui/feature-gates/feature-gate-final-associated-functions.stderr create mode 100644 tests/ui/traits/final/final-kw.gated.stderr create mode 100644 tests/ui/traits/final/final-kw.rs create mode 100644 tests/ui/traits/final/final-kw.ungated.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fa323b7cf581..738435891f16 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3131,8 +3131,16 @@ pub enum Const { /// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532). #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, Walkable)] pub enum Defaultness { + /// Item is unmarked. Implicitly determined based off of position. + /// For impls, this is `final`; for traits, this is `default`. + /// + /// If you're expanding an item in a built-in macro or parsing an item + /// by hand, you probably want to use this. + Implicit, + /// `default` Default(Span), - Final, + /// `final`; per RFC 3678, only trait items may be *explicitly* marked final. + Final(Span), } #[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)] @@ -4140,7 +4148,7 @@ impl AssocItemKind { | Self::Fn(box Fn { defaultness, .. }) | Self::Type(box TyAlias { defaultness, .. }) => defaultness, Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => { - Defaultness::Final + Defaultness::Implicit } } } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 9922ed8a5c58..8ae117f62786 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -939,7 +939,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let trait_item_def_id = hir_id.expect_owner(); - let (ident, generics, kind, has_default) = match &i.kind { + let (ident, generics, kind, has_value) = match &i.kind { AssocItemKind::Const(box ConstItem { ident, generics, @@ -1088,13 +1088,17 @@ impl<'hir> LoweringContext<'_, 'hir> { } }; + let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value, || { + hir::Defaultness::Default { has_value } + }); + let item = hir::TraitItem { owner_id: trait_item_def_id, ident: self.lower_ident(ident), generics, kind, span: self.lower_span(i.span), - defaultness: hir::Defaultness::Default { has_value: has_default }, + defaultness, has_delayed_lints: !self.delayed_lints.is_empty(), }; self.arena.alloc(item) @@ -1122,7 +1126,8 @@ impl<'hir> LoweringContext<'_, 'hir> { // `defaultness.has_value()` is never called for an `impl`, always `true` in order // to not cause an assertion failure inside the `lower_defaultness` function. let has_val = true; - let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val); + let (defaultness, defaultness_span) = + self.lower_defaultness(defaultness, has_val, || hir::Defaultness::Final); let modifiers = TraitBoundModifiers { constness: BoundConstness::Never, asyncness: BoundAsyncness::Normal, @@ -1151,7 +1156,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> &'hir hir::ImplItem<'hir> { // Since `default impl` is not yet implemented, this is always true in impls. let has_value = true; - let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); + let (defaultness, _) = + self.lower_defaultness(i.kind.defaultness(), has_value, || hir::Defaultness::Final); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let attrs = self.lower_attrs( hir_id, @@ -1304,15 +1310,14 @@ impl<'hir> LoweringContext<'_, 'hir> { &self, d: Defaultness, has_value: bool, + implicit: impl FnOnce() -> hir::Defaultness, ) -> (hir::Defaultness, Option) { match d { + Defaultness::Implicit => (implicit(), None), Defaultness::Default(sp) => { (hir::Defaultness::Default { has_value }, Some(self.lower_span(sp))) } - Defaultness::Final => { - assert!(has_value); - (hir::Defaultness::Final, None) - } + Defaultness::Final(sp) => (hir::Defaultness::Final, Some(self.lower_span(sp))), } } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index eac7f03d8450..c902550ae1a6 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -583,6 +583,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(frontmatter, "frontmatters are experimental"); gate_all!(coroutines, "coroutine syntax is experimental"); gate_all!(const_block_items, "const block items are experimental"); + gate_all!(final_associated_functions, "`final` on trait functions is experimental"); if !visitor.features.never_patterns() { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index c7f110a2e003..57e105010343 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -51,7 +51,7 @@ impl<'a> State<'a> { expr.as_deref(), vis, *safety, - ast::Defaultness::Final, + ast::Defaultness::Implicit, define_opaque.as_deref(), ), ast::ForeignItemKind::TyAlias(box ast::TyAlias { @@ -201,7 +201,7 @@ impl<'a> State<'a> { body.as_deref(), &item.vis, ast::Safety::Default, - ast::Defaultness::Final, + ast::Defaultness::Implicit, define_opaque.as_deref(), ); } diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index c87f1e41043d..5f78758513e1 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -83,7 +83,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span let body = Some(cx.block_expr(call)); let kind = ItemKind::Fn(Box::new(Fn { - defaultness: ast::Defaultness::Final, + defaultness: ast::Defaultness::Implicit, sig, ident: Ident::from_str_and_span(&global_fn_name(ALLOC_ERROR_HANDLER), span), generics: Generics::default(), diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 95191b82ff3f..264f797a7825 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -334,7 +334,7 @@ mod llvm_enzyme { // The first element of it is the name of the function to be generated let d_fn = Box::new(ast::Fn { - defaultness: ast::Defaultness::Final, + defaultness: ast::Defaultness::Implicit, sig: d_sig, ident: first_ident(&meta_item_vec[0]), generics, diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 8984e51c0844..1d9551f93a14 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -136,7 +136,7 @@ pub(crate) fn expand_deriving_coerce_pointee( of_trait: Some(Box::new(ast::TraitImplHeader { safety: ast::Safety::Default, polarity: ast::ImplPolarity::Positive, - defaultness: ast::Defaultness::Final, + defaultness: ast::Defaultness::Implicit, trait_ref, })), constness: ast::Const::No, @@ -159,7 +159,7 @@ pub(crate) fn expand_deriving_coerce_pointee( of_trait: Some(Box::new(ast::TraitImplHeader { safety: ast::Safety::Default, polarity: ast::ImplPolarity::Positive, - defaultness: ast::Defaultness::Final, + defaultness: ast::Defaultness::Implicit, trait_ref, })), constness: ast::Const::No, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 3fe5e89ef06d..5362bcde1aad 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -614,7 +614,7 @@ impl<'a> TraitDef<'a> { }, attrs: ast::AttrVec::new(), kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias { - defaultness: ast::Defaultness::Final, + defaultness: ast::Defaultness::Implicit, ident, generics: Generics::default(), after_where_clause: ast::WhereClause::default(), @@ -851,7 +851,7 @@ impl<'a> TraitDef<'a> { of_trait: Some(Box::new(ast::TraitImplHeader { safety: self.safety, polarity: ast::ImplPolarity::Positive, - defaultness: ast::Defaultness::Final, + defaultness: ast::Defaultness::Implicit, trait_ref, })), constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No }, @@ -1073,7 +1073,7 @@ impl<'a> MethodDef<'a> { let trait_lo_sp = span.shrink_to_lo(); let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span }; - let defaultness = ast::Defaultness::Final; + let defaultness = ast::Defaultness::Implicit; // Create the method. Box::new(ast::AssocItem { diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 9e22d408c125..74c13f0fc2fb 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -77,7 +77,7 @@ impl AllocFnFactory<'_, '_> { let sig = FnSig { decl, header, span: self.span }; let body = Some(self.cx.block_expr(result)); let kind = ItemKind::Fn(Box::new(Fn { - defaultness: ast::Defaultness::Final, + defaultness: ast::Defaultness::Implicit, sig, ident: Ident::from_str_and_span(&global_fn_name(method.name), self.span), generics: Generics::default(), diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index a9718d53ac49..45d5daf91327 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -283,7 +283,7 @@ pub(crate) fn expand_test_or_bench( // const $ident: test::TestDescAndFn = ast::ItemKind::Const( ast::ConstItem { - defaultness: ast::Defaultness::Final, + defaultness: ast::Defaultness::Implicit, ident: Ident::new(fn_.ident.name, sp), generics: ast::Generics::default(), ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 8d6969b0ca12..8b89d06c9ec6 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -329,7 +329,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> Box { let decl = ecx.fn_decl(ThinVec::new(), ast::FnRetTy::Ty(main_ret_ty)); let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp }; - let defaultness = ast::Defaultness::Final; + let defaultness = ast::Defaultness::Implicit; // Honor the reexport_test_harness_main attribute let main_ident = match cx.reexport_test_harness_main { diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 7320ee12abe3..19a2d65762e8 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -729,7 +729,7 @@ impl<'a> ExtCtxt<'a> { ty: Box, rhs_kind: ast::ConstItemRhsKind, ) -> Box { - let defaultness = ast::Defaultness::Final; + let defaultness = ast::Defaultness::Implicit; self.item( span, AttrVec::new(), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index add09c3ea58b..9262b08f05e0 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -494,6 +494,8 @@ declare_features! ( (unstable, ffi_const, "1.45.0", Some(58328)), /// Allows the use of `#[ffi_pure]` on foreign functions. (unstable, ffi_pure, "1.45.0", Some(58329)), + /// Allows marking trait functions as `final` to prevent overriding impls + (unstable, final_associated_functions, "CURRENT_RUSTC_VERSION", Some(1)), /// Controlling the behavior of fmt::Debug (unstable, fmt_debug, "1.82.0", Some(129709)), /// Allows using `#[align(...)]` on function items diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 6499f31bb935..05f6f7ba833f 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3795,6 +3795,17 @@ pub(crate) struct RecoverImportAsUse { pub token_name: String, } +#[derive(Diagnostic)] +#[diag("{$article} {$descr} cannot be `final`")] +#[note("only associated functions in traits can be `final`")] +pub(crate) struct InappropriateFinal { + #[primary_span] + #[label("`final` because of this")] + pub span: Span, + pub article: &'static str, + pub descr: &'static str, +} + #[derive(Diagnostic)] #[diag("expected `::`, found `:`")] #[note("import paths are delimited using `::`")] diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 5b81acb0f91f..ae25b82db761 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -206,14 +206,24 @@ impl<'a> Parser<'a> { }) } - /// Error in-case `default` was parsed in an in-appropriate context. + /// Error in-case `default`/`final` was parsed in an in-appropriate context. fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) { - if let Defaultness::Default(span) = def { - self.dcx().emit_err(errors::InappropriateDefault { - span, - article: kind.article(), - descr: kind.descr(), - }); + match def { + Defaultness::Default(span) => { + self.dcx().emit_err(errors::InappropriateDefault { + span, + article: kind.article(), + descr: kind.descr(), + }); + } + Defaultness::Final(span) => { + self.dcx().emit_err(errors::InappropriateFinal { + span, + article: kind.article(), + descr: kind.descr(), + }); + } + Defaultness::Implicit => (), } } @@ -229,8 +239,8 @@ impl<'a> Parser<'a> { fn_parse_mode: FnParseMode, case: Case, ) -> PResult<'a, Option> { - let check_pub = def == &Defaultness::Final; - let mut def_ = || mem::replace(def, Defaultness::Final); + let check_pub = def == &Defaultness::Implicit; + let mut def_ = || mem::replace(def, Defaultness::Implicit); let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) { self.parse_use_item()? @@ -1005,8 +1015,11 @@ impl<'a> Parser<'a> { { self.bump(); // `default` Defaultness::Default(self.prev_token_uninterpolated_span()) + } else if self.eat_keyword(exp!(Final)) { + self.psess.gated_spans.gate(sym::final_associated_functions, self.prev_token.span); + Defaultness::Final(self.prev_token_uninterpolated_span()) } else { - Defaultness::Final + Defaultness::Implicit } } @@ -1130,7 +1143,7 @@ impl<'a> Parser<'a> { }) => { self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span }); AssocItemKind::Const(Box::new(ConstItem { - defaultness: Defaultness::Final, + defaultness: Defaultness::Implicit, ident, generics: Generics::default(), ty, diff --git a/compiler/rustc_parse/src/parser/token_type.rs b/compiler/rustc_parse/src/parser/token_type.rs index 567b1be5e5d9..2d1db430ac27 100644 --- a/compiler/rustc_parse/src/parser/token_type.rs +++ b/compiler/rustc_parse/src/parser/token_type.rs @@ -91,6 +91,7 @@ pub enum TokenType { KwElse, KwEnum, KwExtern, + KwFinal, KwFn, KwFor, KwGen, @@ -233,6 +234,7 @@ impl TokenType { KwExtern, KwFn, KwFor, + KwFinal, KwGen, KwIf, KwImpl, @@ -309,6 +311,7 @@ impl TokenType { TokenType::KwExtern => Some(kw::Extern), TokenType::KwFn => Some(kw::Fn), TokenType::KwFor => Some(kw::For), + TokenType::KwFinal => Some(kw::Final), TokenType::KwGen => Some(kw::Gen), TokenType::KwIf => Some(kw::If), TokenType::KwImpl => Some(kw::Impl), @@ -524,6 +527,7 @@ macro_rules! exp { (Extern) => { exp!(@kw, Extern, KwExtern) }; (Fn) => { exp!(@kw, Fn, KwFn) }; (For) => { exp!(@kw, For, KwFor) }; + (Final) => { exp!(@kw, Final, KwFinal) }; (Gen) => { exp!(@kw, Gen, KwGen) }; (If) => { exp!(@kw, If, KwIf) }; (Impl) => { exp!(@kw, Impl, KwImpl) }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b9a9d8029d28..2cbaf64ff90b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1094,6 +1094,7 @@ symbols! { fields, file, file_options, + final_associated_functions, flags, float, float_to_int_unchecked, diff --git a/tests/ui/coroutine/gen_fn.none.stderr b/tests/ui/coroutine/gen_fn.none.stderr index 590210641aed..8a5f86541316 100644 --- a/tests/ui/coroutine/gen_fn.none.stderr +++ b/tests/ui/coroutine/gen_fn.none.stderr @@ -1,8 +1,8 @@ -error: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen` +error: expected one of `#`, `async`, `const`, `default`, `extern`, `final`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen` --> $DIR/gen_fn.rs:4:1 | LL | gen fn foo() {} - | ^^^ expected one of 10 possible tokens + | ^^^ expected one of 11 possible tokens error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/gen_fn.rs b/tests/ui/coroutine/gen_fn.rs index 2f50d5db9acf..78301cd2832c 100644 --- a/tests/ui/coroutine/gen_fn.rs +++ b/tests/ui/coroutine/gen_fn.rs @@ -2,7 +2,7 @@ //@[e2024] edition: 2024 gen fn foo() {} -//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen` +//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `final`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen` //[e2024]~^^ ERROR: gen blocks are experimental fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-final-associated-functions.rs b/tests/ui/feature-gates/feature-gate-final-associated-functions.rs new file mode 100644 index 000000000000..bdac2710d58e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-final-associated-functions.rs @@ -0,0 +1,6 @@ +trait Foo { + final fn bar() {} + //~^ ERROR `final` on trait functions is experimental +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-final-associated-functions.stderr b/tests/ui/feature-gates/feature-gate-final-associated-functions.stderr new file mode 100644 index 000000000000..b3731acd1d90 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-final-associated-functions.stderr @@ -0,0 +1,13 @@ +error[E0658]: `final` on trait functions is experimental + --> $DIR/feature-gate-final-associated-functions.rs:2:5 + | +LL | final fn bar() {} + | ^^^^^ + | + = note: see issue #1 for more information + = help: add `#![feature(final_associated_functions)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/parser/duplicate-visibility.rs b/tests/ui/parser/duplicate-visibility.rs index f0ee60873da0..d35624981c74 100644 --- a/tests/ui/parser/duplicate-visibility.rs +++ b/tests/ui/parser/duplicate-visibility.rs @@ -2,8 +2,8 @@ fn main() {} extern "C" { //~ NOTE while parsing this item list starting here pub pub fn foo(); - //~^ ERROR expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub` - //~| NOTE expected one of 9 possible tokens + //~^ ERROR expected one of `(`, `async`, `const`, `default`, `extern`, `final`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub` + //~| NOTE expected one of 10 possible tokens //~| HELP there is already a visibility modifier, remove one //~| NOTE explicit visibility first seen here } //~ NOTE the item list ends here diff --git a/tests/ui/parser/duplicate-visibility.stderr b/tests/ui/parser/duplicate-visibility.stderr index 0d1421ee7f4e..e00ebe6a8cf6 100644 --- a/tests/ui/parser/duplicate-visibility.stderr +++ b/tests/ui/parser/duplicate-visibility.stderr @@ -1,4 +1,4 @@ -error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub` +error: expected one of `(`, `async`, `const`, `default`, `extern`, `final`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub` --> $DIR/duplicate-visibility.rs:4:9 | LL | extern "C" { @@ -6,7 +6,7 @@ LL | extern "C" { LL | pub pub fn foo(); | ^^^ | | - | expected one of 9 possible tokens + | expected one of 10 possible tokens | help: there is already a visibility modifier, remove one ... LL | } diff --git a/tests/ui/parser/misspelled-keywords/pub-fn.stderr b/tests/ui/parser/misspelled-keywords/pub-fn.stderr index 1123c652c0ee..9b895f32c91e 100644 --- a/tests/ui/parser/misspelled-keywords/pub-fn.stderr +++ b/tests/ui/parser/misspelled-keywords/pub-fn.stderr @@ -1,8 +1,8 @@ -error: expected one of `#`, `async`, `auto`, `const`, `default`, `enum`, `extern`, `fn`, `gen`, `impl`, `macro_rules`, `macro`, `mod`, `pub`, `safe`, `static`, `struct`, `trait`, `type`, `unsafe`, or `use`, found `puB` +error: expected one of `#`, `async`, `auto`, `const`, `default`, `enum`, `extern`, `final`, `fn`, `gen`, `impl`, `macro_rules`, `macro`, `mod`, `pub`, `safe`, `static`, `struct`, `trait`, `type`, `unsafe`, or `use`, found `puB` --> $DIR/pub-fn.rs:1:1 | LL | puB fn code() {} - | ^^^ expected one of 21 possible tokens + | ^^^ expected one of 22 possible tokens | help: write keyword `pub` in lowercase | diff --git a/tests/ui/traits/final/final-kw.gated.stderr b/tests/ui/traits/final/final-kw.gated.stderr new file mode 100644 index 000000000000..a7967ebf08e2 --- /dev/null +++ b/tests/ui/traits/final/final-kw.gated.stderr @@ -0,0 +1,13 @@ +error[E0658]: `final` on trait functions is experimental + --> $DIR/final-kw.rs:5:5 + | +LL | final fn foo() {} + | ^^^^^ + | + = note: see issue #1 for more information + = help: add `#![feature(final_associated_functions)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/final/final-kw.rs b/tests/ui/traits/final/final-kw.rs new file mode 100644 index 000000000000..ed675dea6608 --- /dev/null +++ b/tests/ui/traits/final/final-kw.rs @@ -0,0 +1,9 @@ +//@ revisions: ungated gated + +#[cfg(ungated)] +trait Trait { + final fn foo() {} + //~^ ERROR `final` on trait functions is experimental +} + +fn main() {} diff --git a/tests/ui/traits/final/final-kw.ungated.stderr b/tests/ui/traits/final/final-kw.ungated.stderr new file mode 100644 index 000000000000..a7967ebf08e2 --- /dev/null +++ b/tests/ui/traits/final/final-kw.ungated.stderr @@ -0,0 +1,13 @@ +error[E0658]: `final` on trait functions is experimental + --> $DIR/final-kw.rs:5:5 + | +LL | final fn foo() {} + | ^^^^^ + | + = note: see issue #1 for more information + = help: add `#![feature(final_associated_functions)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`.