Rollup merge of #151783 - mu001999-contrib:impl/final-method, r=fee1-dead

Implement RFC 3678: Final trait methods

Tracking: https://github.com/rust-lang/rust/issues/131179

This PR is based on rust-lang/rust#130802, with some minor changes and conflict resolution.

Futhermore, this PR excludes final methods from the vtable of a dyn Trait.

And some excerpt from the original PR description:
> Implements the surface part of https://github.com/rust-lang/rfcs/pull/3678.
>
> I'm using the word "method" in the title, but in the diagnostics and the feature gate I used "associated function", since that's more accurate.

cc @joshtriplett
This commit is contained in:
Stuart Cook 2026-02-17 13:02:21 +11:00 committed by GitHub
commit 1367126837
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
57 changed files with 755 additions and 117 deletions

View file

@ -0,0 +1,22 @@
#![feature(final_associated_functions)]
//@ has final_trait_method/trait.Item.html
pub trait Item {
//@ has - '//*[@id="method.foo"]' 'final fn foo()'
//@ !has - '//*[@id="method.foo"]' 'default fn foo()'
final fn foo() {}
//@ has - '//*[@id="method.bar"]' 'fn bar()'
//@ !has - '//*[@id="method.bar"]' 'default fn bar()'
//@ !has - '//*[@id="method.bar"]' 'final fn bar()'
fn bar() {}
}
//@ has final_trait_method/struct.Foo.html
pub struct Foo;
impl Item for Foo {
//@ has - '//*[@id="method.bar"]' 'fn bar()'
//@ !has - '//*[@id="method.bar"]' 'final fn bar()'
//@ !has - '//*[@id="method.bar"]' 'default fn bar()'
fn bar() {}
}

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
|
LL | gen fn foo() {}
| ^^^ expected one of 10 possible tokens
| ^^^ expected one of 11 possible tokens
error: aborting due to 1 previous error

View file

@ -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() {}

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

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
|
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 | }

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

View file

@ -0,0 +1,40 @@
//@ run-pass
#![feature(final_associated_functions)]
trait FinalNoReceiver {
final fn no_receiver() {}
}
trait FinalGeneric {
final fn generic<T>(&self, _value: T) {}
}
trait FinalSelfParam {
final fn self_param(&self, _other: &Self) {}
}
trait FinalSelfReturn {
final fn self_return(&self) -> &Self {
self
}
}
struct S;
impl FinalNoReceiver for S {}
impl FinalGeneric for S {}
impl FinalSelfParam for S {}
impl FinalSelfReturn for S {}
fn main() {
let s = S;
<S as FinalNoReceiver>::no_receiver();
let obj_generic: &dyn FinalGeneric = &s;
let obj_param: &dyn FinalSelfParam = &s;
let obj_return: &dyn FinalSelfReturn = &s;
obj_generic.generic(1u8);
obj_param.self_param(obj_param);
let _ = obj_return.self_return();
let _: &dyn FinalNoReceiver = &s;
}

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`.

View file

@ -0,0 +1,8 @@
#![feature(final_associated_functions)]
trait Foo {
final fn method();
//~^ ERROR `final` is only allowed on associated functions if they have a body
}
fn main() {}

View file

@ -0,0 +1,10 @@
error: `final` is only allowed on associated functions if they have a body
--> $DIR/final-must-have-body.rs:4:5
|
LL | final fn method();
| -----^^^^^^^^^^^^^
| |
| `final` because of this
error: aborting due to 1 previous error

View file

@ -0,0 +1,12 @@
#![feature(final_associated_functions)]
trait Foo {
final fn method() {}
}
impl Foo for () {
fn method() {}
//~^ ERROR cannot override `method` because it already has a `final` definition in the trait
}
fn main() {}

View file

@ -0,0 +1,14 @@
error: cannot override `method` because it already has a `final` definition in the trait
--> $DIR/overriding.rs:8:5
|
LL | fn method() {}
| ^^^^^^^^^^^
|
note: `method` is marked final here
--> $DIR/overriding.rs:4:5
|
LL | final fn method() {}
| ^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -0,0 +1,72 @@
#![feature(final_associated_functions)]
// Just for exercising the syntax positions
#![feature(associated_type_defaults, extern_types, inherent_associated_types)]
#![allow(incomplete_features)]
final struct Foo {}
//~^ ERROR a struct cannot be `final`
final trait Trait {
//~^ ERROR a trait cannot be `final`
final fn method() {}
// OK!
final type Foo = ();
//~^ ERROR `final` is only allowed on associated functions in traits
final const FOO: usize = 1;
//~^ ERROR `final` is only allowed on associated functions in traits
}
final impl Foo {
final fn method() {}
//~^ ERROR `final` is only allowed on associated functions in traits
final type Foo = ();
//~^ ERROR `final` is only allowed on associated functions in traits
final const FOO: usize = 1;
//~^ ERROR `final` is only allowed on associated functions in traits
}
final impl Trait for Foo {
final fn method() {}
//~^ ERROR `final` is only allowed on associated functions in traits
//~^^ ERROR cannot override `method` because it already has a `final` definition in the trait
final type Foo = ();
//~^ ERROR `final` is only allowed on associated functions in traits
//~^^ ERROR cannot override `Foo` because it already has a `final` definition in the trait
final const FOO: usize = 1;
//~^ ERROR `final` is only allowed on associated functions in traits
//~^^ ERROR cannot override `FOO` because it already has a `final` definition in the trait
}
final fn foo() {}
//~^ ERROR `final` is only allowed on associated functions in traits
final type FooTy = ();
//~^ ERROR `final` is only allowed on associated functions in traits
final const FOO: usize = 0;
//~^ ERROR `final` is only allowed on associated functions in traits
final unsafe extern "C" {
//~^ ERROR an extern block cannot be `final`
final fn foo_extern();
//~^ ERROR `final` is only allowed on associated functions in traits
final type FooExtern;
//~^ ERROR `final` is only allowed on associated functions in traits
final static FOO_EXTERN: usize = 0;
//~^ ERROR a static item cannot be `final`
//~| ERROR incorrect `static` inside `extern` block
}
fn main() {}

View file

@ -0,0 +1,187 @@
error: a struct cannot be `final`
--> $DIR/positions.rs:7:1
|
LL | final struct Foo {}
| ^^^^^ `final` because of this
|
= note: only associated functions in traits can be `final`
error: a trait cannot be `final`
--> $DIR/positions.rs:10:1
|
LL | final trait Trait {
| ^^^^^ `final` because of this
|
= note: only associated functions in traits can be `final`
error: a static item cannot be `final`
--> $DIR/positions.rs:67:5
|
LL | final static FOO_EXTERN: usize = 0;
| ^^^^^ `final` because of this
|
= note: only associated functions in traits can be `final`
error: an extern block cannot be `final`
--> $DIR/positions.rs:58:1
|
LL | final unsafe extern "C" {
| ^^^^^ `final` because of this
|
= note: only associated functions in traits can be `final`
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:16:5
|
LL | final type Foo = ();
| -----^^^^^^^^^^^^^^^
| |
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:19:5
|
LL | final const FOO: usize = 1;
| -----^^^^^^^^^^^^^^^^^^^^^^
| |
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:24:5
|
LL | final fn method() {}
| -----^^^^^^^^^^^^
| |
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:27:5
|
LL | final type Foo = ();
| -----^^^^^^^^^^^^^^^
| |
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:30:5
|
LL | final const FOO: usize = 1;
| -----^^^^^^^^^^^^^^^^^^^^^^
| |
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:35:5
|
LL | final fn method() {}
| -----^^^^^^^^^^^^
| |
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:39:5
|
LL | final type Foo = ();
| -----^^^^^^^^^^^^^^^
| |
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:43:5
|
LL | final const FOO: usize = 1;
| -----^^^^^^^^^^^^^^^^^^^^^^
| |
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:49:1
|
LL | final fn foo() {}
| -----^^^^^^^^^
| |
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:52:1
|
LL | final type FooTy = ();
| -----^^^^^^^^^^^^^^^^^
| |
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:55:1
|
LL | final const FOO: usize = 0;
| -----^^^^^^^^^^^^^^^^^^^^^^
| |
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:61:5
|
LL | final fn foo_extern();
| -----^^^^^^^^^^^^^^^^^
| |
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:64:5
|
LL | final type FooExtern;
| -----^^^^^^^^^^^^^^^^
| |
| `final` because of this
error: incorrect `static` inside `extern` block
--> $DIR/positions.rs:67:18
|
LL | final unsafe extern "C" {
| ----------------------- `extern` blocks define existing foreign statics and statics inside of them cannot have a body
...
LL | final static FOO_EXTERN: usize = 0;
| ^^^^^^^^^^ - the invalid body
| |
| cannot have a body
|
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
error: cannot override `method` because it already has a `final` definition in the trait
--> $DIR/positions.rs:35:5
|
LL | final fn method() {}
| ^^^^^^^^^^^^^^^^^
|
note: `method` is marked final here
--> $DIR/positions.rs:13:5
|
LL | final fn method() {}
| ^^^^^^^^^^^^^^^^^
error: cannot override `Foo` because it already has a `final` definition in the trait
--> $DIR/positions.rs:39:5
|
LL | final type Foo = ();
| ^^^^^^^^^^^^^^
|
note: `Foo` is marked final here
--> $DIR/positions.rs:16:5
|
LL | final type Foo = ();
| ^^^^^^^^^^^^^^
error: cannot override `FOO` because it already has a `final` definition in the trait
--> $DIR/positions.rs:43:5
|
LL | final const FOO: usize = 1;
| ^^^^^^^^^^^^^^^^^^^^^^
|
note: `FOO` is marked final here
--> $DIR/positions.rs:19:5
|
LL | final const FOO: usize = 1;
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 21 previous errors

View file

@ -0,0 +1,13 @@
//@ check-pass
#![feature(final_associated_functions)]
trait Foo {
final fn bar(&self) {}
}
impl Foo for () {}
fn main() {
().bar();
}