Skip to content

Commit bd928a0

Browse files
committed
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`.
1 parent dd9a7bf commit bd928a0

File tree

11 files changed

+112
-23
lines changed

11 files changed

+112
-23
lines changed

compiler/rustc_data_structures/src/owned_slice.rs

+2
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,11 @@ impl Borrow<[u8]> for OwnedSlice {
109109
}
110110

111111
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Send`
112+
#[cfg(parallel_compiler)]
112113
unsafe impl Send for OwnedSlice {}
113114

114115
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Sync`
116+
#[cfg(parallel_compiler)]
115117
unsafe impl Sync for OwnedSlice {}
116118

117119
#[cfg(test)]

compiler/rustc_hir_analysis/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,9 @@ hir_analysis_specialization_trait = implementing `rustc_specialization_trait` tr
275275
hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present
276276
.label = `for<...>` is here
277277
278+
hir_analysis_empty_specialization = specialization impl does not specialize any associated items
279+
.note = impl is a specialization of this impl
280+
278281
hir_analysis_const_specialize = cannot specialize on const impl with non-const impl
279282
280283
hir_analysis_static_specialize = cannot specialize on `'static` lifetime

compiler/rustc_hir_analysis/src/errors.rs

+9
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,15 @@ pub(crate) struct ClosureImplicitHrtb {
803803
pub for_sp: Span,
804804
}
805805

806+
#[derive(Diagnostic)]
807+
#[diag(hir_analysis_empty_specialization)]
808+
pub(crate) struct EmptySpecialization {
809+
#[primary_span]
810+
pub span: Span,
811+
#[note]
812+
pub base_impl_span: Span,
813+
}
814+
806815
#[derive(Diagnostic)]
807816
#[diag(hir_analysis_const_specialize)]
808817
pub(crate) struct ConstSpecialize {

compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,19 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti
100100
// Implementing a normal trait isn't a specialization.
101101
return None;
102102
}
103+
if trait_def.is_marker {
104+
// Overlapping marker implementations are not really specializations.
105+
return None;
106+
}
103107
Some(impl2_node)
104108
}
105109

106110
/// Check that `impl1` is a sound specialization
107111
#[instrument(level = "debug", skip(tcx))]
108112
fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node) {
113+
let span = tcx.def_span(impl1_def_id);
114+
check_has_items(tcx, impl1_def_id, impl2_node, span);
115+
109116
if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) {
110117
let impl2_def_id = impl2_node.def_id();
111118
debug!(?impl2_def_id, ?impl2_substs);
@@ -116,14 +123,20 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
116123
unconstrained_parent_impl_substs(tcx, impl2_def_id, impl2_substs)
117124
};
118125

119-
let span = tcx.def_span(impl1_def_id);
120126
check_constness(tcx, impl1_def_id, impl2_node, span);
121127
check_static_lifetimes(tcx, &parent_substs, span);
122128
check_duplicate_params(tcx, impl1_substs, &parent_substs, span);
123129
check_predicates(tcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span);
124130
}
125131
}
126132

133+
fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
134+
if let Node::Impl(impl2_id) = impl2_node && tcx.associated_item_def_ids(impl1_def_id).is_empty() {
135+
let base_impl_span = tcx.def_span(impl2_id);
136+
tcx.sess.emit_err(errors::EmptySpecialization { span, base_impl_span });
137+
}
138+
}
139+
127140
/// Check that the specializing impl `impl1` is at least as const as the base
128141
/// impl `impl2`
129142
fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {

compiler/rustc_middle/src/mir/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -2728,8 +2728,6 @@ pub struct UserTypeProjection {
27282728
pub projs: Vec<ProjectionKind>,
27292729
}
27302730

2731-
impl Copy for ProjectionKind {}
2732-
27332731
impl UserTypeProjection {
27342732
pub(crate) fn index(mut self) -> Self {
27352733
self.projs.push(ProjectionElem::Index(()));

tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ trait Specialize {}
1212
trait Foo {}
1313

1414
#[const_trait]
15-
trait Bar {}
15+
trait Bar {
16+
fn bar();
17+
}
1618

1719
// bgr360: I was only able to exercise the code path that raises the
1820
// "missing ~const qualifier" error by making this base impl non-const, even
@@ -21,26 +23,36 @@ trait Bar {}
2123
impl<T> Bar for T
2224
where
2325
T: ~const Foo,
24-
{}
26+
{
27+
default fn bar() {}
28+
}
2529

2630
impl<T> Bar for T
2731
where
2832
T: Foo, //~ ERROR missing `~const` qualifier
2933
T: Specialize,
30-
{}
34+
{
35+
fn bar() {}
36+
}
3137

3238
#[const_trait]
33-
trait Baz {}
39+
trait Baz {
40+
fn baz();
41+
}
3442

3543
impl<T> const Baz for T
3644
where
3745
T: ~const Foo,
38-
{}
46+
{
47+
default fn baz() {}
48+
}
3949

4050
impl<T> const Baz for T //~ ERROR conflicting implementations of trait `Baz`
4151
where
4252
T: Foo,
4353
T: Specialize,
44-
{}
54+
{
55+
fn baz() {}
56+
}
4557

4658
fn main() {}

tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error: missing `~const` qualifier for specialization
2-
--> $DIR/const-default-bound-non-const-specialized-bound.rs:28:8
2+
--> $DIR/const-default-bound-non-const-specialized-bound.rs:32:8
33
|
44
LL | T: Foo,
55
| ^^^
66

77
error[E0119]: conflicting implementations of trait `Baz`
8-
--> $DIR/const-default-bound-non-const-specialized-bound.rs:40:1
8+
--> $DIR/const-default-bound-non-const-specialized-bound.rs:50:1
99
|
1010
LL | impl<T> const Baz for T
1111
| ----------------------- first implementation here

tests/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,39 @@
1111
trait Specialize {}
1212

1313
#[const_trait]
14-
trait Foo {}
14+
trait Foo {
15+
fn foo();
16+
}
1517

16-
impl<T> const Foo for T {}
18+
impl<T> const Foo for T {
19+
default fn foo() {}
20+
}
1721

1822
impl<T> const Foo for T
1923
where
2024
T: ~const Specialize,
21-
{}
25+
{
26+
fn foo() {}
27+
}
2228

2329
#[const_trait]
24-
trait Bar {}
30+
trait Bar {
31+
fn bar() {}
32+
}
2533

2634
impl<T> const Bar for T
2735
where
2836
T: ~const Foo,
29-
{}
37+
{
38+
default fn bar() {}
39+
}
3040

3141
impl<T> const Bar for T
3242
where
3343
T: ~const Foo,
3444
T: ~const Specialize,
35-
{}
45+
{
46+
fn bar() {}
47+
}
3648

3749
fn main() {}

tests/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,43 @@ trait Specialize {}
1515
trait Foo {}
1616

1717
#[const_trait]
18-
trait Bar {}
18+
trait Bar {
19+
fn bar();
20+
}
1921

2022
impl<T> Bar for T
2123
where
2224
T: Foo,
23-
{}
25+
{
26+
default fn bar() {}
27+
}
2428

2529
impl<T> const Bar for T
2630
where
2731
T: ~const Foo,
2832
T: Specialize,
29-
{}
33+
{
34+
fn bar() {}
35+
}
3036

3137
#[const_trait]
32-
trait Baz {}
38+
trait Baz {
39+
fn baz();
40+
}
3341

3442
impl<T> const Baz for T
3543
where
3644
T: Foo,
37-
{}
45+
{
46+
default fn baz() {}
47+
}
3848

3949
impl<T> const Baz for T
4050
where
4151
T: ~const Foo,
4252
T: Specialize,
43-
{}
53+
{
54+
fn baz() {}
55+
}
4456

4557
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![feature(min_specialization)]
2+
3+
trait Special {
4+
fn be_special();
5+
}
6+
7+
impl<T> Special for T {
8+
fn be_special() {}
9+
}
10+
11+
impl Special for usize {}
12+
//~^ ERROR specialization impl does not specialize any associated items
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: specialization impl does not specialize any associated items
2+
--> $DIR/specialize_nothing.rs:11:1
3+
|
4+
LL | impl Special for usize {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
note: impl is a specialization of this impl
8+
--> $DIR/specialize_nothing.rs:7:1
9+
|
10+
LL | impl<T> Special for T {
11+
| ^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: aborting due to previous error
14+

0 commit comments

Comments
 (0)