From bd928a0b5e144b0fafb2f4659a83aa362de7e3c7 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 5 May 2023 12:54:58 +0100 Subject: [PATCH] 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`. --- .../rustc_data_structures/src/owned_slice.rs | 2 ++ compiler/rustc_hir_analysis/messages.ftl | 3 +++ compiler/rustc_hir_analysis/src/errors.rs | 9 +++++++ .../src/impl_wf_check/min_specialization.rs | 15 +++++++++++- compiler/rustc_middle/src/mir/mod.rs | 2 -- ...fault-bound-non-const-specialized-bound.rs | 24 ++++++++++++++----- ...t-bound-non-const-specialized-bound.stderr | 4 ++-- .../issue-95186-specialize-on-tilde-const.rs | 24 ++++++++++++++----- ...87-same-trait-bound-different-constness.rs | 24 ++++++++++++++----- .../min_specialization/specialize_nothing.rs | 14 +++++++++++ .../specialize_nothing.stderr | 14 +++++++++++ 11 files changed, 112 insertions(+), 23 deletions(-) create mode 100644 tests/ui/specialization/min_specialization/specialize_nothing.rs create mode 100644 tests/ui/specialization/min_specialization/specialize_nothing.stderr diff --git a/compiler/rustc_data_structures/src/owned_slice.rs b/compiler/rustc_data_structures/src/owned_slice.rs index 048401f66c2..311a42aa42a 100644 --- a/compiler/rustc_data_structures/src/owned_slice.rs +++ b/compiler/rustc_data_structures/src/owned_slice.rs @@ -109,9 +109,11 @@ impl Borrow<[u8]> for OwnedSlice { } // Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box)`, which is `Send` +#[cfg(parallel_compiler)] unsafe impl Send for OwnedSlice {} // Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box)`, which is `Sync` +#[cfg(parallel_compiler)] unsafe impl Sync for OwnedSlice {} #[cfg(test)] diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index eaa75bde6c6..c130eaae755 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -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 .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_static_specialize = cannot specialize on `'static` lifetime diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index c0ee777722e..32e91af2608 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -803,6 +803,15 @@ pub(crate) struct ClosureImplicitHrtb { 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)] #[diag(hir_analysis_const_specialize)] pub(crate) struct ConstSpecialize { diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 5cca2dacb5c..4f0df5c5677 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -100,12 +100,19 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti // Implementing a normal trait isn't a specialization. return None; } + if trait_def.is_marker { + // Overlapping marker implementations are not really specializations. + return None; + } Some(impl2_node) } /// Check that `impl1` is a sound specialization #[instrument(level = "debug", skip(tcx))] 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) { let impl2_def_id = impl2_node.def_id(); 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) }; - let span = tcx.def_span(impl1_def_id); check_constness(tcx, impl1_def_id, impl2_node, span); check_static_lifetimes(tcx, &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 /// impl `impl2` fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 858a3d266ea..f2841182a1a 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2728,8 +2728,6 @@ pub struct UserTypeProjection { pub projs: Vec, } -impl Copy for ProjectionKind {} - impl UserTypeProjection { pub(crate) fn index(mut self) -> Self { self.projs.push(ProjectionElem::Index(())); diff --git a/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs b/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs index 3ac90992486..f31123f16f1 100644 --- a/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs +++ b/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs @@ -12,7 +12,9 @@ trait Specialize {} trait Foo {} #[const_trait] -trait Bar {} +trait Bar { + fn bar(); +} // 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 @@ -21,26 +23,36 @@ trait Bar {} impl Bar for T where T: ~const Foo, -{} +{ + default fn bar() {} +} impl Bar for T where T: Foo, //~ ERROR missing `~const` qualifier T: Specialize, -{} +{ + fn bar() {} +} #[const_trait] -trait Baz {} +trait Baz { + fn baz(); +} impl const Baz for T where T: ~const Foo, -{} +{ + default fn baz() {} +} impl const Baz for T //~ ERROR conflicting implementations of trait `Baz` where T: Foo, T: Specialize, -{} +{ + fn baz() {} +} fn main() {} diff --git a/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr index 4aea1979421..057cf4aea8a 100644 --- a/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr +++ b/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr @@ -1,11 +1,11 @@ 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, | ^^^ 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 const Baz for T | ----------------------- first implementation here diff --git a/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs b/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs index 9c2c2cf1610..92d8be6bb16 100644 --- a/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs +++ b/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs @@ -11,27 +11,39 @@ trait Specialize {} #[const_trait] -trait Foo {} +trait Foo { + fn foo(); +} -impl const Foo for T {} +impl const Foo for T { + default fn foo() {} +} impl const Foo for T where T: ~const Specialize, -{} +{ + fn foo() {} +} #[const_trait] -trait Bar {} +trait Bar { + fn bar() {} +} impl const Bar for T where T: ~const Foo, -{} +{ + default fn bar() {} +} impl const Bar for T where T: ~const Foo, T: ~const Specialize, -{} +{ + fn bar() {} +} fn main() {} diff --git a/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs b/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs index 1e6b1c6513b..51bfaf73b57 100644 --- a/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs +++ b/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs @@ -15,31 +15,43 @@ trait Specialize {} trait Foo {} #[const_trait] -trait Bar {} +trait Bar { + fn bar(); +} impl Bar for T where T: Foo, -{} +{ + default fn bar() {} +} impl const Bar for T where T: ~const Foo, T: Specialize, -{} +{ + fn bar() {} +} #[const_trait] -trait Baz {} +trait Baz { + fn baz(); +} impl const Baz for T where T: Foo, -{} +{ + default fn baz() {} +} impl const Baz for T where T: ~const Foo, T: Specialize, -{} +{ + fn baz() {} +} fn main() {} diff --git a/tests/ui/specialization/min_specialization/specialize_nothing.rs b/tests/ui/specialization/min_specialization/specialize_nothing.rs new file mode 100644 index 00000000000..ef92254d465 --- /dev/null +++ b/tests/ui/specialization/min_specialization/specialize_nothing.rs @@ -0,0 +1,14 @@ +#![feature(min_specialization)] + +trait Special { + fn be_special(); +} + +impl Special for T { + fn be_special() {} +} + +impl Special for usize {} +//~^ ERROR specialization impl does not specialize any associated items + +fn main() {} diff --git a/tests/ui/specialization/min_specialization/specialize_nothing.stderr b/tests/ui/specialization/min_specialization/specialize_nothing.stderr new file mode 100644 index 00000000000..65f73781cae --- /dev/null +++ b/tests/ui/specialization/min_specialization/specialize_nothing.stderr @@ -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 Special for T { + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error +