Skip to content

Commit 9bda88b

Browse files
Fix const specialization
1 parent e91fc1b commit 9bda88b

11 files changed

+133
-50
lines changed

Diff for: compiler/rustc_hir_analysis/messages.ftl

-2
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,6 @@ hir_analysis_const_param_ty_impl_on_unsized =
113113
the trait `ConstParamTy` may not be implemented for this type
114114
.label = type is not `Sized`
115115
116-
hir_analysis_const_specialize = cannot specialize on const impl with non-const impl
117-
118116
hir_analysis_copy_impl_on_non_adt =
119117
the trait `Copy` cannot be implemented for this type
120118
.label = type is not a structure or enumeration

Diff for: compiler/rustc_hir_analysis/src/errors.rs

-7
Original file line numberDiff line numberDiff line change
@@ -1079,13 +1079,6 @@ pub(crate) struct EmptySpecialization {
10791079
pub base_impl_span: Span,
10801080
}
10811081

1082-
#[derive(Diagnostic)]
1083-
#[diag(hir_analysis_const_specialize)]
1084-
pub(crate) struct ConstSpecialize {
1085-
#[primary_span]
1086-
pub span: Span,
1087-
}
1088-
10891082
#[derive(Diagnostic)]
10901083
#[diag(hir_analysis_static_specialize)]
10911084
pub(crate) struct StaticSpecialize {

Diff for: compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs

-26
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@
6666
//! on traits with methods can.
6767
6868
use rustc_data_structures::fx::FxHashSet;
69-
use rustc_hir as hir;
7069
use rustc_hir::def_id::{DefId, LocalDefId};
7170
use rustc_infer::infer::TyCtxtInferExt;
7271
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
@@ -134,7 +133,6 @@ fn check_always_applicable(
134133
unconstrained_parent_impl_args(tcx, impl2_def_id, impl2_args)
135134
};
136135

137-
res = res.and(check_constness(tcx, impl1_def_id, impl2_node, span));
138136
res = res.and(check_static_lifetimes(tcx, &parent_args, span));
139137
res = res.and(check_duplicate_params(tcx, impl1_args, parent_args, span));
140138
res = res.and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span));
@@ -157,30 +155,6 @@ fn check_has_items(
157155
Ok(())
158156
}
159157

160-
/// Check that the specializing impl `impl1` is at least as const as the base
161-
/// impl `impl2`
162-
fn check_constness(
163-
tcx: TyCtxt<'_>,
164-
impl1_def_id: LocalDefId,
165-
impl2_node: Node,
166-
span: Span,
167-
) -> Result<(), ErrorGuaranteed> {
168-
if impl2_node.is_from_trait() {
169-
// This isn't a specialization
170-
return Ok(());
171-
}
172-
173-
let impl1_constness = tcx.constness(impl1_def_id.to_def_id());
174-
let impl2_constness = tcx.constness(impl2_node.def_id());
175-
176-
if let hir::Constness::Const = impl2_constness {
177-
if let hir::Constness::NotConst = impl1_constness {
178-
return Err(tcx.dcx().emit_err(errors::ConstSpecialize { span }));
179-
}
180-
}
181-
Ok(())
182-
}
183-
184158
/// Given a specializing impl `impl1`, and the base impl `impl2`, returns two
185159
/// generic parameters `(S1, S2)` that equate their trait references.
186160
/// The returned types are expressed in terms of the generics of `impl1`.

Diff for: compiler/rustc_trait_selection/src/traits/specialize/mod.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,17 @@ pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool
225225
tcx.features().specialization() || tcx.features().min_specialization()
226226
}
227227

228-
/// Is `impl1` a specialization of `impl2`?
228+
/// Is `specializing_impl_def_id` a specialization of `parent_impl_def_id`?
229229
///
230-
/// Specialization is determined by the sets of types to which the impls apply;
231-
/// `impl1` specializes `impl2` if it applies to a subset of the types `impl2` applies
232-
/// to.
230+
/// For every type that could apply to `specializing_impl_def_id`, we prove that
231+
/// the `parent_impl_def_id` also applies (i.e. it has a valid impl header and
232+
/// its where-clauses hold).
233+
///
234+
/// For the purposes of const traits, we also check that the specializing
235+
/// impl is not more restrictive than the parent impl. That is, if the
236+
/// `parent_impl_def_id` is a const impl (conditionally based off of some `~const`
237+
/// bounds), then `specializing_impl_def_id` must also be const for the same
238+
/// set of types.
233239
#[instrument(skip(tcx), level = "debug")]
234240
pub(super) fn specializes(
235241
tcx: TyCtxt<'_>,
@@ -339,8 +345,14 @@ pub(super) fn specializes(
339345
return false;
340346
}
341347

342-
// If the parent impl is const, then the specializing impl must be const.
348+
// If the parent impl is const, then the specializing impl must be const,
349+
// and it must not be *more restrictive* than the parent impl (that is,
350+
// it cannot be const in fewer cases than the parent impl).
343351
if tcx.is_conditionally_const(parent_impl_def_id) {
352+
if !tcx.is_conditionally_const(specializing_impl_def_id) {
353+
return false;
354+
}
355+
344356
let const_conditions = ocx.normalize(
345357
cause,
346358
param_env,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0119]: conflicting implementations of trait `Foo` for type `(_,)`
2+
--> $DIR/overlap-const-with-nonconst.rs:23:1
3+
|
4+
LL | / impl<T> const Foo for T
5+
LL | | where
6+
LL | | T: ~const Bar,
7+
| |__________________- first implementation here
8+
...
9+
LL | impl<T> Foo for (T,) {
10+
| ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_,)`
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0119`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//@ revisions: spec min_spec
2+
3+
#![feature(const_trait_impl)]
4+
#![cfg_attr(spec, feature(specialization))]
5+
//[spec]~^ WARN the feature `specialization` is incomplete
6+
#![cfg_attr(min_spec, feature(min_specialization))]
7+
8+
#[const_trait]
9+
trait Bar {}
10+
impl<T> const Bar for T {}
11+
12+
#[const_trait]
13+
trait Foo {
14+
fn method(&self);
15+
}
16+
impl<T> const Foo for T
17+
where
18+
T: ~const Bar,
19+
{
20+
default fn method(&self) {}
21+
}
22+
// specializing impl:
23+
impl<T> Foo for (T,) {
24+
//~^ ERROR conflicting implementations
25+
fn method(&self) {
26+
println!("hi");
27+
}
28+
}
29+
30+
const fn dispatch<T: ~const Bar + Copy>(t: T) {
31+
t.method();
32+
}
33+
34+
fn main() {
35+
const {
36+
dispatch(((),));
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/overlap-const-with-nonconst.rs:4:27
3+
|
4+
LL | #![cfg_attr(spec, feature(specialization))]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
8+
= help: consider using `min_specialization` instead, which is more stable and complete
9+
= note: `#[warn(incomplete_features)]` on by default
10+
11+
error[E0119]: conflicting implementations of trait `Foo` for type `(_,)`
12+
--> $DIR/overlap-const-with-nonconst.rs:23:1
13+
|
14+
LL | / impl<T> const Foo for T
15+
LL | | where
16+
LL | | T: ~const Bar,
17+
| |__________________- first implementation here
18+
...
19+
LL | impl<T> Foo for (T,) {
20+
| ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_,)`
21+
22+
error: aborting due to 1 previous error; 1 warning emitted
23+
24+
For more information about this error, try `rustc --explain E0119`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0119]: conflicting implementations of trait `Value` for type `FortyTwo`
2+
--> $DIR/const-default-impl-non-const-specialized-impl.rs:22:1
3+
|
4+
LL | impl<T> const Value for T {
5+
| ------------------------- first implementation here
6+
...
7+
LL | impl Value for FortyTwo {
8+
| ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `FortyTwo`
9+
10+
error: aborting due to 1 previous error
11+
12+
For more information about this error, try `rustc --explain E0119`.

Diff for: tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
// Tests that specializing trait impls must be at least as const as the default impl.
2+
//@ revisions: spec min_spec
23

34
#![feature(const_trait_impl)]
4-
#![feature(min_specialization)]
5+
#![cfg_attr(spec, feature(specialization))]
6+
//[spec]~^ WARN the feature `specialization` is incomplete
7+
#![cfg_attr(min_spec, feature(min_specialization))]
58

69
#[const_trait]
710
trait Value {
@@ -16,7 +19,8 @@ impl<T> const Value for T {
1619

1720
struct FortyTwo;
1821

19-
impl Value for FortyTwo { //~ ERROR cannot specialize on const impl with non-const impl
22+
impl Value for FortyTwo {
23+
//~^ ERROR conflicting implementations
2024
fn value() -> u32 {
2125
println!("You can't do that (constly)");
2226
42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/const-default-impl-non-const-specialized-impl.rs:5:27
3+
|
4+
LL | #![cfg_attr(spec, feature(specialization))]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
8+
= help: consider using `min_specialization` instead, which is more stable and complete
9+
= note: `#[warn(incomplete_features)]` on by default
10+
11+
error[E0119]: conflicting implementations of trait `Value` for type `FortyTwo`
12+
--> $DIR/const-default-impl-non-const-specialized-impl.rs:22:1
13+
|
14+
LL | impl<T> const Value for T {
15+
| ------------------------- first implementation here
16+
...
17+
LL | impl Value for FortyTwo {
18+
| ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `FortyTwo`
19+
20+
error: aborting due to 1 previous error; 1 warning emitted
21+
22+
For more information about this error, try `rustc --explain E0119`.

Diff for: tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr

-8
This file was deleted.

0 commit comments

Comments
 (0)