Skip to content

Commit e57e5f0

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

File tree

4 files changed

+75
-11
lines changed

4 files changed

+75
-11
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: 23 additions & 4 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
}
@@ -247,16 +251,31 @@ fn super_predicates_have_non_lifetime_binders(
247251
tcx: TyCtxt<'_>,
248252
trait_def_id: DefId,
249253
) -> SmallVec<[Span; 1]> {
250-
// If non_lifetime_binders is disabled, then exit early
251-
if !tcx.features().non_lifetime_binders() {
252-
return SmallVec::new();
253-
}
254254
tcx.explicit_super_predicates_of(trait_def_id)
255255
.iter_identity_copied()
256256
.filter_map(|(pred, span)| pred.has_non_region_bound_vars().then_some(span))
257257
.collect()
258258
}
259259

260+
/// Checks for `const Trait` supertraits. We're okay with `[const] Trait`,
261+
/// supertraits since for a non-const instantiation of that trait, the
262+
/// conditionally-const supertrait is also not required to be const.
263+
fn super_predicates_are_unconditionally_const(
264+
tcx: TyCtxt<'_>,
265+
trait_def_id: DefId,
266+
) -> SmallVec<[Span; 1]> {
267+
tcx.explicit_super_predicates_of(trait_def_id)
268+
.iter_identity_copied()
269+
.filter_map(|(pred, span)| {
270+
if let ty::ClauseKind::HostEffect(_) = pred.kind().skip_binder() {
271+
Some(span)
272+
} else {
273+
None
274+
}
275+
})
276+
.collect()
277+
}
278+
260279
fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
261280
tcx.generics_require_sized_self(trait_def_id)
262281
}
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)