Validate no override impl definitions

Co-authored-by: Michael Goulet <michael@errs.io>
This commit is contained in:
mu001999
2026-01-28 21:59:42 +08:00
parent 460cda8c95
commit 3572d482a0
8 changed files with 124 additions and 24 deletions
+25 -1
View File
@@ -1175,13 +1175,35 @@ pub(super) fn check_specialization_validity<'tcx>(
if let Err(parent_impl) = result {
if !tcx.is_impl_trait_in_trait(impl_item) {
report_forbidden_specialization(tcx, impl_item, parent_impl);
let span = tcx.def_span(impl_item);
let ident = tcx.item_ident(impl_item);
let err = match tcx.span_of_impl(parent_impl) {
Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
};
tcx.dcx().emit_err(err);
} else {
tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default"));
}
}
}
fn check_overriding_final_trait_item<'tcx>(
tcx: TyCtxt<'tcx>,
trait_item: ty::AssocItem,
impl_item: ty::AssocItem,
) {
if trait_item.defaultness(tcx).is_final() {
tcx.dcx().emit_err(errors::OverridingFinalTraitFunction {
impl_span: tcx.def_span(impl_item.def_id),
trait_span: tcx.def_span(trait_item.def_id),
ident: tcx.item_ident(impl_item.def_id),
});
}
}
fn check_impl_items_against_trait<'tcx>(
tcx: TyCtxt<'tcx>,
impl_id: LocalDefId,
@@ -1259,6 +1281,8 @@ fn check_impl_items_against_trait<'tcx>(
impl_id.to_def_id(),
impl_item,
);
check_overriding_final_trait_item(tcx, ty_trait_item, ty_impl_item);
}
if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
@@ -197,18 +197,6 @@ pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDef
}
}
fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_impl: DefId) {
let span = tcx.def_span(impl_item);
let ident = tcx.item_ident(impl_item);
let err = match tcx.span_of_impl(parent_impl) {
Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
};
tcx.dcx().emit_err(err);
}
fn missing_items_err(
tcx: TyCtxt<'_>,
impl_def_id: LocalDefId,
+10
View File
@@ -892,6 +892,16 @@ pub(crate) enum ImplNotMarkedDefault {
#[diag("this item cannot be used as its where bounds are not satisfied for the `Self` type")]
pub(crate) struct UselessImplItem;
#[derive(Diagnostic)]
#[diag("cannot override `{$ident}` because it already has a `final` definition in the trait")]
pub(crate) struct OverridingFinalTraitFunction {
#[primary_span]
pub impl_span: Span,
#[note("`{$ident}` is marked final here")]
pub trait_span: Span,
pub ident: Ident,
}
#[derive(Diagnostic)]
#[diag("not all trait items implemented, missing: `{$missing_items_msg}`", code = E0046)]
pub(crate) struct MissingTraitItem {
+12
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() {}
+14
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
+3
View File
@@ -34,12 +34,15 @@
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
}
+47 -11
View File
@@ -15,7 +15,7 @@ LL | final trait Trait {
= note: only associated functions in traits can be `final`
error: a static item cannot be `final`
--> $DIR/positions.rs:64:5
--> $DIR/positions.rs:67:5
|
LL | final static FOO_EXTERN: usize = 0;
| ^^^^^ `final` because of this
@@ -23,7 +23,7 @@ LL | final static FOO_EXTERN: usize = 0;
= note: only associated functions in traits can be `final`
error: an extern block cannot be `final`
--> $DIR/positions.rs:55:1
--> $DIR/positions.rs:58:1
|
LL | final unsafe extern "C" {
| ^^^^^ `final` because of this
@@ -79,7 +79,7 @@ LL | final fn method() {}
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:38:5
--> $DIR/positions.rs:39:5
|
LL | final type Foo = ();
| -----^^^^^^^^^^^^^^^
@@ -87,7 +87,7 @@ LL | final type Foo = ();
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:41:5
--> $DIR/positions.rs:43:5
|
LL | final const FOO: usize = 1;
| -----^^^^^^^^^^^^^^^^^^^^^^
@@ -95,7 +95,7 @@ LL | final const FOO: usize = 1;
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:46:1
--> $DIR/positions.rs:49:1
|
LL | final fn foo() {}
| -----^^^^^^^^^
@@ -103,7 +103,7 @@ LL | final fn foo() {}
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:49:1
--> $DIR/positions.rs:52:1
|
LL | final type FooTy = ();
| -----^^^^^^^^^^^^^^^^^
@@ -111,7 +111,7 @@ LL | final type FooTy = ();
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:52:1
--> $DIR/positions.rs:55:1
|
LL | final const FOO: usize = 0;
| -----^^^^^^^^^^^^^^^^^^^^^^
@@ -119,7 +119,7 @@ LL | final const FOO: usize = 0;
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:58:5
--> $DIR/positions.rs:61:5
|
LL | final fn foo_extern();
| -----^^^^^^^^^^^^^^^^^
@@ -127,7 +127,7 @@ LL | final fn foo_extern();
| `final` because of this
error: `final` is only allowed on associated functions in traits
--> $DIR/positions.rs:61:5
--> $DIR/positions.rs:64:5
|
LL | final type FooExtern;
| -----^^^^^^^^^^^^^^^^
@@ -135,7 +135,7 @@ LL | final type FooExtern;
| `final` because of this
error: incorrect `static` inside `extern` block
--> $DIR/positions.rs:64:18
--> $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
@@ -147,5 +147,41 @@ LL | final static FOO_EXTERN: usize = 0;
|
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
error: aborting due to 18 previous errors
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
+13
View File
@@ -0,0 +1,13 @@
//@ check-pass
#![feature(final_associated_functions)]
trait Foo {
final fn bar(&self) {}
}
impl Foo for () {}
fn main() {
().bar();
}