Parse and lower final for methods

Co-authored-by: Michael Goulet <michael@errs.io>
This commit is contained in:
mu001999 2026-01-28 21:19:09 +08:00
parent 605f49b274
commit 7077797f52
27 changed files with 142 additions and 43 deletions

View file

@ -3131,8 +3131,16 @@ pub enum Const {
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532). /// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, Walkable)] #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
pub enum Defaultness { 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), 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)] #[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
@ -4140,7 +4148,7 @@ impl AssocItemKind {
| Self::Fn(box Fn { defaultness, .. }) | Self::Fn(box Fn { defaultness, .. })
| Self::Type(box TyAlias { defaultness, .. }) => defaultness, | Self::Type(box TyAlias { defaultness, .. }) => defaultness,
Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => { Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
Defaultness::Final Defaultness::Implicit
} }
} }
} }

View file

@ -939,7 +939,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
); );
let trait_item_def_id = hir_id.expect_owner(); 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 { AssocItemKind::Const(box ConstItem {
ident, ident,
generics, 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 { let item = hir::TraitItem {
owner_id: trait_item_def_id, owner_id: trait_item_def_id,
ident: self.lower_ident(ident), ident: self.lower_ident(ident),
generics, generics,
kind, kind,
span: self.lower_span(i.span), span: self.lower_span(i.span),
defaultness: hir::Defaultness::Default { has_value: has_default }, defaultness,
has_delayed_lints: !self.delayed_lints.is_empty(), has_delayed_lints: !self.delayed_lints.is_empty(),
}; };
self.arena.alloc(item) 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 // `defaultness.has_value()` is never called for an `impl`, always `true` in order
// to not cause an assertion failure inside the `lower_defaultness` function. // to not cause an assertion failure inside the `lower_defaultness` function.
let has_val = true; 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 { let modifiers = TraitBoundModifiers {
constness: BoundConstness::Never, constness: BoundConstness::Never,
asyncness: BoundAsyncness::Normal, asyncness: BoundAsyncness::Normal,
@ -1151,7 +1156,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
) -> &'hir hir::ImplItem<'hir> { ) -> &'hir hir::ImplItem<'hir> {
// Since `default impl` is not yet implemented, this is always true in impls. // Since `default impl` is not yet implemented, this is always true in impls.
let has_value = true; 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 hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
let attrs = self.lower_attrs( let attrs = self.lower_attrs(
hir_id, hir_id,
@ -1304,15 +1310,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
&self, &self,
d: Defaultness, d: Defaultness,
has_value: bool, has_value: bool,
implicit: impl FnOnce() -> hir::Defaultness,
) -> (hir::Defaultness, Option<Span>) { ) -> (hir::Defaultness, Option<Span>) {
match d { match d {
Defaultness::Implicit => (implicit(), None),
Defaultness::Default(sp) => { Defaultness::Default(sp) => {
(hir::Defaultness::Default { has_value }, Some(self.lower_span(sp))) (hir::Defaultness::Default { has_value }, Some(self.lower_span(sp)))
} }
Defaultness::Final => { Defaultness::Final(sp) => (hir::Defaultness::Final, Some(self.lower_span(sp))),
assert!(has_value);
(hir::Defaultness::Final, None)
}
} }
} }

View file

@ -583,6 +583,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(frontmatter, "frontmatters are experimental"); gate_all!(frontmatter, "frontmatters are experimental");
gate_all!(coroutines, "coroutine syntax is experimental"); gate_all!(coroutines, "coroutine syntax is experimental");
gate_all!(const_block_items, "const block items are 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 !visitor.features.never_patterns() {
if let Some(spans) = spans.get(&sym::never_patterns) { if let Some(spans) = spans.get(&sym::never_patterns) {

View file

@ -51,7 +51,7 @@ impl<'a> State<'a> {
expr.as_deref(), expr.as_deref(),
vis, vis,
*safety, *safety,
ast::Defaultness::Final, ast::Defaultness::Implicit,
define_opaque.as_deref(), define_opaque.as_deref(),
), ),
ast::ForeignItemKind::TyAlias(box ast::TyAlias { ast::ForeignItemKind::TyAlias(box ast::TyAlias {
@ -201,7 +201,7 @@ impl<'a> State<'a> {
body.as_deref(), body.as_deref(),
&item.vis, &item.vis,
ast::Safety::Default, ast::Safety::Default,
ast::Defaultness::Final, ast::Defaultness::Implicit,
define_opaque.as_deref(), define_opaque.as_deref(),
); );
} }

View file

@ -83,7 +83,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
let body = Some(cx.block_expr(call)); let body = Some(cx.block_expr(call));
let kind = ItemKind::Fn(Box::new(Fn { let kind = ItemKind::Fn(Box::new(Fn {
defaultness: ast::Defaultness::Final, defaultness: ast::Defaultness::Implicit,
sig, sig,
ident: Ident::from_str_and_span(&global_fn_name(ALLOC_ERROR_HANDLER), span), ident: Ident::from_str_and_span(&global_fn_name(ALLOC_ERROR_HANDLER), span),
generics: Generics::default(), generics: Generics::default(),

View file

@ -334,7 +334,7 @@ mod llvm_enzyme {
// The first element of it is the name of the function to be generated // The first element of it is the name of the function to be generated
let d_fn = Box::new(ast::Fn { let d_fn = Box::new(ast::Fn {
defaultness: ast::Defaultness::Final, defaultness: ast::Defaultness::Implicit,
sig: d_sig, sig: d_sig,
ident: first_ident(&meta_item_vec[0]), ident: first_ident(&meta_item_vec[0]),
generics, generics,

View file

@ -136,7 +136,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
of_trait: Some(Box::new(ast::TraitImplHeader { of_trait: Some(Box::new(ast::TraitImplHeader {
safety: ast::Safety::Default, safety: ast::Safety::Default,
polarity: ast::ImplPolarity::Positive, polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final, defaultness: ast::Defaultness::Implicit,
trait_ref, trait_ref,
})), })),
constness: ast::Const::No, constness: ast::Const::No,
@ -159,7 +159,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
of_trait: Some(Box::new(ast::TraitImplHeader { of_trait: Some(Box::new(ast::TraitImplHeader {
safety: ast::Safety::Default, safety: ast::Safety::Default,
polarity: ast::ImplPolarity::Positive, polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final, defaultness: ast::Defaultness::Implicit,
trait_ref, trait_ref,
})), })),
constness: ast::Const::No, constness: ast::Const::No,

View file

@ -614,7 +614,7 @@ impl<'a> TraitDef<'a> {
}, },
attrs: ast::AttrVec::new(), attrs: ast::AttrVec::new(),
kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias { kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
defaultness: ast::Defaultness::Final, defaultness: ast::Defaultness::Implicit,
ident, ident,
generics: Generics::default(), generics: Generics::default(),
after_where_clause: ast::WhereClause::default(), after_where_clause: ast::WhereClause::default(),
@ -851,7 +851,7 @@ impl<'a> TraitDef<'a> {
of_trait: Some(Box::new(ast::TraitImplHeader { of_trait: Some(Box::new(ast::TraitImplHeader {
safety: self.safety, safety: self.safety,
polarity: ast::ImplPolarity::Positive, polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final, defaultness: ast::Defaultness::Implicit,
trait_ref, trait_ref,
})), })),
constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No }, 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 trait_lo_sp = span.shrink_to_lo();
let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span }; 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. // Create the method.
Box::new(ast::AssocItem { Box::new(ast::AssocItem {

View file

@ -77,7 +77,7 @@ impl AllocFnFactory<'_, '_> {
let sig = FnSig { decl, header, span: self.span }; let sig = FnSig { decl, header, span: self.span };
let body = Some(self.cx.block_expr(result)); let body = Some(self.cx.block_expr(result));
let kind = ItemKind::Fn(Box::new(Fn { let kind = ItemKind::Fn(Box::new(Fn {
defaultness: ast::Defaultness::Final, defaultness: ast::Defaultness::Implicit,
sig, sig,
ident: Ident::from_str_and_span(&global_fn_name(method.name), self.span), ident: Ident::from_str_and_span(&global_fn_name(method.name), self.span),
generics: Generics::default(), generics: Generics::default(),

View file

@ -283,7 +283,7 @@ pub(crate) fn expand_test_or_bench(
// const $ident: test::TestDescAndFn = // const $ident: test::TestDescAndFn =
ast::ItemKind::Const( ast::ItemKind::Const(
ast::ConstItem { ast::ConstItem {
defaultness: ast::Defaultness::Final, defaultness: ast::Defaultness::Implicit,
ident: Ident::new(fn_.ident.name, sp), ident: Ident::new(fn_.ident.name, sp),
generics: ast::Generics::default(), generics: ast::Generics::default(),
ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),

View file

@ -329,7 +329,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> Box<ast::Item> {
let decl = ecx.fn_decl(ThinVec::new(), ast::FnRetTy::Ty(main_ret_ty)); 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 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 // Honor the reexport_test_harness_main attribute
let main_ident = match cx.reexport_test_harness_main { let main_ident = match cx.reexport_test_harness_main {

View file

@ -729,7 +729,7 @@ impl<'a> ExtCtxt<'a> {
ty: Box<ast::Ty>, ty: Box<ast::Ty>,
rhs_kind: ast::ConstItemRhsKind, rhs_kind: ast::ConstItemRhsKind,
) -> Box<ast::Item> { ) -> Box<ast::Item> {
let defaultness = ast::Defaultness::Final; let defaultness = ast::Defaultness::Implicit;
self.item( self.item(
span, span,
AttrVec::new(), AttrVec::new(),

View file

@ -494,6 +494,8 @@ declare_features! (
(unstable, ffi_const, "1.45.0", Some(58328)), (unstable, ffi_const, "1.45.0", Some(58328)),
/// Allows the use of `#[ffi_pure]` on foreign functions. /// Allows the use of `#[ffi_pure]` on foreign functions.
(unstable, ffi_pure, "1.45.0", Some(58329)), (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 /// Controlling the behavior of fmt::Debug
(unstable, fmt_debug, "1.82.0", Some(129709)), (unstable, fmt_debug, "1.82.0", Some(129709)),
/// Allows using `#[align(...)]` on function items /// Allows using `#[align(...)]` on function items

View file

@ -3795,6 +3795,17 @@ pub(crate) struct RecoverImportAsUse {
pub token_name: String, 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)] #[derive(Diagnostic)]
#[diag("expected `::`, found `:`")] #[diag("expected `::`, found `:`")]
#[note("import paths are delimited using `::`")] #[note("import paths are delimited using `::`")]

View file

@ -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) { fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) {
if let Defaultness::Default(span) = def { match def {
self.dcx().emit_err(errors::InappropriateDefault { Defaultness::Default(span) => {
span, self.dcx().emit_err(errors::InappropriateDefault {
article: kind.article(), span,
descr: kind.descr(), 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, fn_parse_mode: FnParseMode,
case: Case, case: Case,
) -> PResult<'a, Option<ItemKind>> { ) -> PResult<'a, Option<ItemKind>> {
let check_pub = def == &Defaultness::Final; let check_pub = def == &Defaultness::Implicit;
let mut def_ = || mem::replace(def, Defaultness::Final); let mut def_ = || mem::replace(def, Defaultness::Implicit);
let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) { let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) {
self.parse_use_item()? self.parse_use_item()?
@ -1005,8 +1015,11 @@ impl<'a> Parser<'a> {
{ {
self.bump(); // `default` self.bump(); // `default`
Defaultness::Default(self.prev_token_uninterpolated_span()) 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 { } else {
Defaultness::Final Defaultness::Implicit
} }
} }
@ -1130,7 +1143,7 @@ impl<'a> Parser<'a> {
}) => { }) => {
self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span }); self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span });
AssocItemKind::Const(Box::new(ConstItem { AssocItemKind::Const(Box::new(ConstItem {
defaultness: Defaultness::Final, defaultness: Defaultness::Implicit,
ident, ident,
generics: Generics::default(), generics: Generics::default(),
ty, ty,

View file

@ -91,6 +91,7 @@ pub enum TokenType {
KwElse, KwElse,
KwEnum, KwEnum,
KwExtern, KwExtern,
KwFinal,
KwFn, KwFn,
KwFor, KwFor,
KwGen, KwGen,
@ -233,6 +234,7 @@ impl TokenType {
KwExtern, KwExtern,
KwFn, KwFn,
KwFor, KwFor,
KwFinal,
KwGen, KwGen,
KwIf, KwIf,
KwImpl, KwImpl,
@ -309,6 +311,7 @@ impl TokenType {
TokenType::KwExtern => Some(kw::Extern), TokenType::KwExtern => Some(kw::Extern),
TokenType::KwFn => Some(kw::Fn), TokenType::KwFn => Some(kw::Fn),
TokenType::KwFor => Some(kw::For), TokenType::KwFor => Some(kw::For),
TokenType::KwFinal => Some(kw::Final),
TokenType::KwGen => Some(kw::Gen), TokenType::KwGen => Some(kw::Gen),
TokenType::KwIf => Some(kw::If), TokenType::KwIf => Some(kw::If),
TokenType::KwImpl => Some(kw::Impl), TokenType::KwImpl => Some(kw::Impl),
@ -524,6 +527,7 @@ macro_rules! exp {
(Extern) => { exp!(@kw, Extern, KwExtern) }; (Extern) => { exp!(@kw, Extern, KwExtern) };
(Fn) => { exp!(@kw, Fn, KwFn) }; (Fn) => { exp!(@kw, Fn, KwFn) };
(For) => { exp!(@kw, For, KwFor) }; (For) => { exp!(@kw, For, KwFor) };
(Final) => { exp!(@kw, Final, KwFinal) };
(Gen) => { exp!(@kw, Gen, KwGen) }; (Gen) => { exp!(@kw, Gen, KwGen) };
(If) => { exp!(@kw, If, KwIf) }; (If) => { exp!(@kw, If, KwIf) };
(Impl) => { exp!(@kw, Impl, KwImpl) }; (Impl) => { exp!(@kw, Impl, KwImpl) };

View file

@ -1094,6 +1094,7 @@ symbols! {
fields, fields,
file, file,
file_options, file_options,
final_associated_functions,
flags, flags,
float, float,
float_to_int_unchecked, float_to_int_unchecked,

View file

@ -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 --> $DIR/gen_fn.rs:4:1
| |
LL | gen fn foo() {} LL | gen fn foo() {}
| ^^^ expected one of 10 possible tokens | ^^^ expected one of 11 possible tokens
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -2,7 +2,7 @@
//@[e2024] edition: 2024 //@[e2024] edition: 2024
gen fn foo() {} 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 //[e2024]~^^ ERROR: gen blocks are experimental
fn main() {} fn main() {}

View file

@ -0,0 +1,6 @@
trait Foo {
final fn bar() {}
//~^ ERROR `final` on trait functions is experimental
}
fn main() {}

View file

@ -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 <https://github.com/rust-lang/rust/issues/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`.

View file

@ -2,8 +2,8 @@ fn main() {}
extern "C" { //~ NOTE while parsing this item list starting here extern "C" { //~ NOTE while parsing this item list starting here
pub pub fn foo(); pub pub fn foo();
//~^ 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`
//~| NOTE expected one of 9 possible tokens //~| NOTE expected one of 10 possible tokens
//~| HELP there is already a visibility modifier, remove one //~| HELP there is already a visibility modifier, remove one
//~| NOTE explicit visibility first seen here //~| NOTE explicit visibility first seen here
} //~ NOTE the item list ends here } //~ NOTE the item list ends here

View file

@ -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 --> $DIR/duplicate-visibility.rs:4:9
| |
LL | extern "C" { LL | extern "C" {
@ -6,7 +6,7 @@ LL | extern "C" {
LL | pub pub fn foo(); 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 | help: there is already a visibility modifier, remove one
... ...
LL | } LL | }

View file

@ -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 --> $DIR/pub-fn.rs:1:1
| |
LL | puB fn code() {} LL | puB fn code() {}
| ^^^ expected one of 21 possible tokens | ^^^ expected one of 22 possible tokens
| |
help: write keyword `pub` in lowercase help: write keyword `pub` in lowercase
| |

View file

@ -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 <https://github.com/rust-lang/rust/issues/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`.

View file

@ -0,0 +1,9 @@
//@ revisions: ungated gated
#[cfg(ungated)]
trait Trait {
final fn foo() {}
//~^ ERROR `final` on trait functions is experimental
}
fn main() {}

View file

@ -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 <https://github.com/rust-lang/rust/issues/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`.