Disallow (min) specialization imps with no items
Such implementations are usually mistakes and are not used in the compiler or standard library (after this commit) so forbid them with `min_specialization`.
This commit is contained in:
parent
dd9a7bf848
commit
bd928a0b5e
11 changed files with 112 additions and 23 deletions
|
@ -109,9 +109,11 @@ impl Borrow<[u8]> for OwnedSlice {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Send`
|
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Send`
|
||||||
|
#[cfg(parallel_compiler)]
|
||||||
unsafe impl Send for OwnedSlice {}
|
unsafe impl Send for OwnedSlice {}
|
||||||
|
|
||||||
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Sync`
|
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Sync`
|
||||||
|
#[cfg(parallel_compiler)]
|
||||||
unsafe impl Sync for OwnedSlice {}
|
unsafe impl Sync for OwnedSlice {}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -275,6 +275,9 @@ hir_analysis_specialization_trait = implementing `rustc_specialization_trait` tr
|
||||||
hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present
|
hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present
|
||||||
.label = `for<...>` is here
|
.label = `for<...>` is here
|
||||||
|
|
||||||
|
hir_analysis_empty_specialization = specialization impl does not specialize any associated items
|
||||||
|
.note = impl is a specialization of this impl
|
||||||
|
|
||||||
hir_analysis_const_specialize = cannot specialize on const impl with non-const impl
|
hir_analysis_const_specialize = cannot specialize on const impl with non-const impl
|
||||||
|
|
||||||
hir_analysis_static_specialize = cannot specialize on `'static` lifetime
|
hir_analysis_static_specialize = cannot specialize on `'static` lifetime
|
||||||
|
|
|
@ -803,6 +803,15 @@ pub(crate) struct ClosureImplicitHrtb {
|
||||||
pub for_sp: Span,
|
pub for_sp: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis_empty_specialization)]
|
||||||
|
pub(crate) struct EmptySpecialization {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
#[note]
|
||||||
|
pub base_impl_span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_analysis_const_specialize)]
|
#[diag(hir_analysis_const_specialize)]
|
||||||
pub(crate) struct ConstSpecialize {
|
pub(crate) struct ConstSpecialize {
|
||||||
|
|
|
@ -100,12 +100,19 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti
|
||||||
// Implementing a normal trait isn't a specialization.
|
// Implementing a normal trait isn't a specialization.
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
if trait_def.is_marker {
|
||||||
|
// Overlapping marker implementations are not really specializations.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
Some(impl2_node)
|
Some(impl2_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check that `impl1` is a sound specialization
|
/// Check that `impl1` is a sound specialization
|
||||||
#[instrument(level = "debug", skip(tcx))]
|
#[instrument(level = "debug", skip(tcx))]
|
||||||
fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node) {
|
fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node) {
|
||||||
|
let span = tcx.def_span(impl1_def_id);
|
||||||
|
check_has_items(tcx, impl1_def_id, impl2_node, span);
|
||||||
|
|
||||||
if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) {
|
if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) {
|
||||||
let impl2_def_id = impl2_node.def_id();
|
let impl2_def_id = impl2_node.def_id();
|
||||||
debug!(?impl2_def_id, ?impl2_substs);
|
debug!(?impl2_def_id, ?impl2_substs);
|
||||||
|
@ -116,7 +123,6 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
|
||||||
unconstrained_parent_impl_substs(tcx, impl2_def_id, impl2_substs)
|
unconstrained_parent_impl_substs(tcx, impl2_def_id, impl2_substs)
|
||||||
};
|
};
|
||||||
|
|
||||||
let span = tcx.def_span(impl1_def_id);
|
|
||||||
check_constness(tcx, impl1_def_id, impl2_node, span);
|
check_constness(tcx, impl1_def_id, impl2_node, span);
|
||||||
check_static_lifetimes(tcx, &parent_substs, span);
|
check_static_lifetimes(tcx, &parent_substs, span);
|
||||||
check_duplicate_params(tcx, impl1_substs, &parent_substs, span);
|
check_duplicate_params(tcx, impl1_substs, &parent_substs, span);
|
||||||
|
@ -124,6 +130,13 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
|
||||||
|
if let Node::Impl(impl2_id) = impl2_node && tcx.associated_item_def_ids(impl1_def_id).is_empty() {
|
||||||
|
let base_impl_span = tcx.def_span(impl2_id);
|
||||||
|
tcx.sess.emit_err(errors::EmptySpecialization { span, base_impl_span });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Check that the specializing impl `impl1` is at least as const as the base
|
/// Check that the specializing impl `impl1` is at least as const as the base
|
||||||
/// impl `impl2`
|
/// impl `impl2`
|
||||||
fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
|
fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
|
||||||
|
|
|
@ -2728,8 +2728,6 @@ pub struct UserTypeProjection {
|
||||||
pub projs: Vec<ProjectionKind>,
|
pub projs: Vec<ProjectionKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Copy for ProjectionKind {}
|
|
||||||
|
|
||||||
impl UserTypeProjection {
|
impl UserTypeProjection {
|
||||||
pub(crate) fn index(mut self) -> Self {
|
pub(crate) fn index(mut self) -> Self {
|
||||||
self.projs.push(ProjectionElem::Index(()));
|
self.projs.push(ProjectionElem::Index(()));
|
||||||
|
|
|
@ -12,7 +12,9 @@ trait Specialize {}
|
||||||
trait Foo {}
|
trait Foo {}
|
||||||
|
|
||||||
#[const_trait]
|
#[const_trait]
|
||||||
trait Bar {}
|
trait Bar {
|
||||||
|
fn bar();
|
||||||
|
}
|
||||||
|
|
||||||
// bgr360: I was only able to exercise the code path that raises the
|
// bgr360: I was only able to exercise the code path that raises the
|
||||||
// "missing ~const qualifier" error by making this base impl non-const, even
|
// "missing ~const qualifier" error by making this base impl non-const, even
|
||||||
|
@ -21,26 +23,36 @@ trait Bar {}
|
||||||
impl<T> Bar for T
|
impl<T> Bar for T
|
||||||
where
|
where
|
||||||
T: ~const Foo,
|
T: ~const Foo,
|
||||||
{}
|
{
|
||||||
|
default fn bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Bar for T
|
impl<T> Bar for T
|
||||||
where
|
where
|
||||||
T: Foo, //~ ERROR missing `~const` qualifier
|
T: Foo, //~ ERROR missing `~const` qualifier
|
||||||
T: Specialize,
|
T: Specialize,
|
||||||
{}
|
{
|
||||||
|
fn bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
#[const_trait]
|
#[const_trait]
|
||||||
trait Baz {}
|
trait Baz {
|
||||||
|
fn baz();
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> const Baz for T
|
impl<T> const Baz for T
|
||||||
where
|
where
|
||||||
T: ~const Foo,
|
T: ~const Foo,
|
||||||
{}
|
{
|
||||||
|
default fn baz() {}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> const Baz for T //~ ERROR conflicting implementations of trait `Baz`
|
impl<T> const Baz for T //~ ERROR conflicting implementations of trait `Baz`
|
||||||
where
|
where
|
||||||
T: Foo,
|
T: Foo,
|
||||||
T: Specialize,
|
T: Specialize,
|
||||||
{}
|
{
|
||||||
|
fn baz() {}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
error: missing `~const` qualifier for specialization
|
error: missing `~const` qualifier for specialization
|
||||||
--> $DIR/const-default-bound-non-const-specialized-bound.rs:28:8
|
--> $DIR/const-default-bound-non-const-specialized-bound.rs:32:8
|
||||||
|
|
|
|
||||||
LL | T: Foo,
|
LL | T: Foo,
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error[E0119]: conflicting implementations of trait `Baz`
|
error[E0119]: conflicting implementations of trait `Baz`
|
||||||
--> $DIR/const-default-bound-non-const-specialized-bound.rs:40:1
|
--> $DIR/const-default-bound-non-const-specialized-bound.rs:50:1
|
||||||
|
|
|
|
||||||
LL | impl<T> const Baz for T
|
LL | impl<T> const Baz for T
|
||||||
| ----------------------- first implementation here
|
| ----------------------- first implementation here
|
||||||
|
|
|
@ -11,27 +11,39 @@
|
||||||
trait Specialize {}
|
trait Specialize {}
|
||||||
|
|
||||||
#[const_trait]
|
#[const_trait]
|
||||||
trait Foo {}
|
trait Foo {
|
||||||
|
fn foo();
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> const Foo for T {}
|
impl<T> const Foo for T {
|
||||||
|
default fn foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> const Foo for T
|
impl<T> const Foo for T
|
||||||
where
|
where
|
||||||
T: ~const Specialize,
|
T: ~const Specialize,
|
||||||
{}
|
{
|
||||||
|
fn foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
#[const_trait]
|
#[const_trait]
|
||||||
trait Bar {}
|
trait Bar {
|
||||||
|
fn bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> const Bar for T
|
impl<T> const Bar for T
|
||||||
where
|
where
|
||||||
T: ~const Foo,
|
T: ~const Foo,
|
||||||
{}
|
{
|
||||||
|
default fn bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> const Bar for T
|
impl<T> const Bar for T
|
||||||
where
|
where
|
||||||
T: ~const Foo,
|
T: ~const Foo,
|
||||||
T: ~const Specialize,
|
T: ~const Specialize,
|
||||||
{}
|
{
|
||||||
|
fn bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -15,31 +15,43 @@ trait Specialize {}
|
||||||
trait Foo {}
|
trait Foo {}
|
||||||
|
|
||||||
#[const_trait]
|
#[const_trait]
|
||||||
trait Bar {}
|
trait Bar {
|
||||||
|
fn bar();
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Bar for T
|
impl<T> Bar for T
|
||||||
where
|
where
|
||||||
T: Foo,
|
T: Foo,
|
||||||
{}
|
{
|
||||||
|
default fn bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> const Bar for T
|
impl<T> const Bar for T
|
||||||
where
|
where
|
||||||
T: ~const Foo,
|
T: ~const Foo,
|
||||||
T: Specialize,
|
T: Specialize,
|
||||||
{}
|
{
|
||||||
|
fn bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
#[const_trait]
|
#[const_trait]
|
||||||
trait Baz {}
|
trait Baz {
|
||||||
|
fn baz();
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> const Baz for T
|
impl<T> const Baz for T
|
||||||
where
|
where
|
||||||
T: Foo,
|
T: Foo,
|
||||||
{}
|
{
|
||||||
|
default fn baz() {}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> const Baz for T
|
impl<T> const Baz for T
|
||||||
where
|
where
|
||||||
T: ~const Foo,
|
T: ~const Foo,
|
||||||
T: Specialize,
|
T: Specialize,
|
||||||
{}
|
{
|
||||||
|
fn baz() {}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
#![feature(min_specialization)]
|
||||||
|
|
||||||
|
trait Special {
|
||||||
|
fn be_special();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Special for T {
|
||||||
|
fn be_special() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Special for usize {}
|
||||||
|
//~^ ERROR specialization impl does not specialize any associated items
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,14 @@
|
||||||
|
error: specialization impl does not specialize any associated items
|
||||||
|
--> $DIR/specialize_nothing.rs:11:1
|
||||||
|
|
|
||||||
|
LL | impl Special for usize {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: impl is a specialization of this impl
|
||||||
|
--> $DIR/specialize_nothing.rs:7:1
|
||||||
|
|
|
||||||
|
LL | impl<T> Special for T {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue