Skip to content

Commit a65a29d

Browse files
Unconditionally-const supertraits are considered not dyn compatible
1 parent 239e8b1 commit a65a29d

File tree

4 files changed

+78
-7
lines changed

4 files changed

+78
-7
lines changed

compiler/rustc_middle/src/traits/mod.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,9 @@ pub enum DynCompatibilityViolation {
760760
// Supertrait has a non-lifetime `for<T>` binder.
761761
SupertraitNonLifetimeBinder(SmallVec<[Span; 1]>),
762762

763+
// Trait has a `const Trait` supertrait.
764+
SupertraitConst(SmallVec<[Span; 1]>),
765+
763766
/// Method has something illegal.
764767
Method(Symbol, MethodViolationCode, Span),
765768

@@ -785,6 +788,9 @@ impl DynCompatibilityViolation {
785788
DynCompatibilityViolation::SupertraitNonLifetimeBinder(_) => {
786789
"where clause cannot reference non-lifetime `for<...>` variables".into()
787790
}
791+
DynCompatibilityViolation::SupertraitConst(_) => {
792+
"it cannot have a `const` supertrait".into()
793+
}
788794
DynCompatibilityViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
789795
format!("associated function `{name}` has no `self` parameter").into()
790796
}
@@ -842,7 +848,8 @@ impl DynCompatibilityViolation {
842848
match self {
843849
DynCompatibilityViolation::SizedSelf(_)
844850
| DynCompatibilityViolation::SupertraitSelf(_)
845-
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(..) => {
851+
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(..)
852+
| DynCompatibilityViolation::SupertraitConst(_) => {
846853
DynCompatibilityViolationSolution::None
847854
}
848855
DynCompatibilityViolation::Method(
@@ -873,15 +880,17 @@ impl DynCompatibilityViolation {
873880
match self {
874881
DynCompatibilityViolation::SupertraitSelf(spans)
875882
| DynCompatibilityViolation::SizedSelf(spans)
876-
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans) => spans.clone(),
883+
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans)
884+
| DynCompatibilityViolation::SupertraitConst(spans) => spans.clone(),
877885
DynCompatibilityViolation::AssocConst(_, span)
878886
| DynCompatibilityViolation::GAT(_, span)
879-
| DynCompatibilityViolation::Method(_, _, span)
880-
if *span != DUMMY_SP =>
881-
{
882-
smallvec![*span]
887+
| DynCompatibilityViolation::Method(_, _, span) => {
888+
if *span != DUMMY_SP {
889+
smallvec![*span]
890+
} else {
891+
smallvec![]
892+
}
883893
}
884-
_ => smallvec![],
885894
}
886895
}
887896
}

compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ fn dyn_compatibility_violations_for_trait(
106106
if !spans.is_empty() {
107107
violations.push(DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans));
108108
}
109+
let spans = super_predicates_are_unconditionally_const(tcx, trait_def_id);
110+
if !spans.is_empty() {
111+
violations.push(DynCompatibilityViolation::SupertraitConst(spans));
112+
}
109113

110114
violations
111115
}
@@ -257,6 +261,28 @@ fn super_predicates_have_non_lifetime_binders(
257261
.collect()
258262
}
259263

264+
/// Checks for `const Trait` supertraits. We're okay with `[const] Trait`,
265+
/// supertraits since for a non-const instantiation of that trait, the
266+
/// conditionally-const supertrait is also not required to be const.
267+
fn super_predicates_are_unconditionally_const(
268+
tcx: TyCtxt<'_>,
269+
trait_def_id: DefId,
270+
) -> SmallVec<[Span; 1]> {
271+
if !tcx.features().const_trait_impl() {
272+
return SmallVec::new();
273+
}
274+
tcx.explicit_super_predicates_of(trait_def_id)
275+
.iter_identity_copied()
276+
.filter_map(|(pred, span)| {
277+
if let ty::ClauseKind::HostEffect(_) = pred.kind().skip_binder() {
278+
Some(span)
279+
} else {
280+
None
281+
}
282+
})
283+
.collect()
284+
}
285+
260286
fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
261287
tcx.generics_require_sized_self(trait_def_id)
262288
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#![feature(const_trait_impl)]
2+
3+
const trait Super {}
4+
5+
// Not ok
6+
const trait Unconditionally: const Super {}
7+
fn test() {
8+
let _: &dyn Unconditionally;
9+
//~^ ERROR the trait `Unconditionally` is not dyn compatible
10+
}
11+
12+
// Okay
13+
const trait Conditionally: [const] Super {}
14+
fn test2() {
15+
let _: &dyn Conditionally;
16+
}
17+
18+
fn main() {}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0038]: the trait `Unconditionally` is not dyn compatible
2+
--> $DIR/const-supertraits-dyn-compat.rs:8:17
3+
|
4+
LL | let _: &dyn Unconditionally;
5+
| ^^^^^^^^^^^^^^^ `Unconditionally` is not dyn compatible
6+
|
7+
note: for a trait to be dyn compatible it needs to allow building a vtable
8+
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
9+
--> $DIR/const-supertraits-dyn-compat.rs:6:30
10+
|
11+
LL | const trait Unconditionally: const Super {}
12+
| --------------- ^^^^^^^^^^^ ...because it cannot have a `const` supertrait
13+
| |
14+
| this trait is not dyn compatible...
15+
16+
error: aborting due to 1 previous error
17+
18+
For more information about this error, try `rustc --explain E0038`.

0 commit comments

Comments
 (0)