mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-28 19:27:30 +03:00
Validate no override impl definitions
Co-authored-by: Michael Goulet <michael@errs.io>
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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() {}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
//@ check-pass
|
||||
|
||||
#![feature(final_associated_functions)]
|
||||
|
||||
trait Foo {
|
||||
final fn bar(&self) {}
|
||||
}
|
||||
|
||||
impl Foo for () {}
|
||||
|
||||
fn main() {
|
||||
().bar();
|
||||
}
|
||||
Reference in New Issue
Block a user