Skip to content

Unconditionally-const supertraits are considered not dyn compatible #145627

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,9 @@ pub enum DynCompatibilityViolation {
// Supertrait has a non-lifetime `for<T>` binder.
SupertraitNonLifetimeBinder(SmallVec<[Span; 1]>),

// Trait has a `const Trait` supertrait.
SupertraitConst(SmallVec<[Span; 1]>),

/// Method has something illegal.
Method(Symbol, MethodViolationCode, Span),

Expand All @@ -785,6 +788,9 @@ impl DynCompatibilityViolation {
DynCompatibilityViolation::SupertraitNonLifetimeBinder(_) => {
"where clause cannot reference non-lifetime `for<...>` variables".into()
}
DynCompatibilityViolation::SupertraitConst(_) => {
"it cannot have a `const` supertrait".into()
}
DynCompatibilityViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
format!("associated function `{name}` has no `self` parameter").into()
}
Expand Down Expand Up @@ -842,7 +848,8 @@ impl DynCompatibilityViolation {
match self {
DynCompatibilityViolation::SizedSelf(_)
| DynCompatibilityViolation::SupertraitSelf(_)
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(..) => {
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(..)
| DynCompatibilityViolation::SupertraitConst(_) => {
DynCompatibilityViolationSolution::None
}
DynCompatibilityViolation::Method(
Expand Down Expand Up @@ -873,15 +880,17 @@ impl DynCompatibilityViolation {
match self {
DynCompatibilityViolation::SupertraitSelf(spans)
| DynCompatibilityViolation::SizedSelf(spans)
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans) => spans.clone(),
| DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans)
| DynCompatibilityViolation::SupertraitConst(spans) => spans.clone(),
DynCompatibilityViolation::AssocConst(_, span)
| DynCompatibilityViolation::GAT(_, span)
| DynCompatibilityViolation::Method(_, _, span)
if *span != DUMMY_SP =>
{
smallvec![*span]
| DynCompatibilityViolation::Method(_, _, span) => {
if *span != DUMMY_SP {
smallvec![*span]
} else {
smallvec![]
}
}
_ => smallvec![],
}
}
}
Expand Down
27 changes: 23 additions & 4 deletions compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ fn dyn_compatibility_violations_for_trait(
if !spans.is_empty() {
violations.push(DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans));
}
let spans = super_predicates_are_unconditionally_const(tcx, trait_def_id);
if !spans.is_empty() {
violations.push(DynCompatibilityViolation::SupertraitConst(spans));
}

violations
}
Expand Down Expand Up @@ -247,16 +251,31 @@ fn super_predicates_have_non_lifetime_binders(
tcx: TyCtxt<'_>,
trait_def_id: DefId,
) -> SmallVec<[Span; 1]> {
// If non_lifetime_binders is disabled, then exit early
if !tcx.features().non_lifetime_binders() {
return SmallVec::new();
}
tcx.explicit_super_predicates_of(trait_def_id)
.iter_identity_copied()
.filter_map(|(pred, span)| pred.has_non_region_bound_vars().then_some(span))
.collect()
}

/// Checks for `const Trait` supertraits. We're okay with `[const] Trait`,
/// supertraits since for a non-const instantiation of that trait, the
/// conditionally-const supertrait is also not required to be const.
fn super_predicates_are_unconditionally_const(
tcx: TyCtxt<'_>,
trait_def_id: DefId,
) -> SmallVec<[Span; 1]> {
tcx.explicit_super_predicates_of(trait_def_id)
.iter_identity_copied()
.filter_map(|(pred, span)| {
if let ty::ClauseKind::HostEffect(_) = pred.kind().skip_binder() {
Some(span)
} else {
None
}
})
.collect()
}

fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
tcx.generics_require_sized_self(trait_def_id)
}
Expand Down
18 changes: 18 additions & 0 deletions tests/ui/traits/const-traits/const-supertraits-dyn-compat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#![feature(const_trait_impl)]

const trait Super {}

// Not ok
const trait Unconditionally: const Super {}
fn test() {
let _: &dyn Unconditionally;
//~^ ERROR the trait `Unconditionally` is not dyn compatible
}

// Okay
const trait Conditionally: [const] Super {}
fn test2() {
let _: &dyn Conditionally;
}

fn main() {}
18 changes: 18 additions & 0 deletions tests/ui/traits/const-traits/const-supertraits-dyn-compat.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error[E0038]: the trait `Unconditionally` is not dyn compatible
--> $DIR/const-supertraits-dyn-compat.rs:8:17
|
LL | let _: &dyn Unconditionally;
| ^^^^^^^^^^^^^^^ `Unconditionally` is not dyn compatible
|
note: for a trait to be dyn compatible it needs to allow building a vtable
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $DIR/const-supertraits-dyn-compat.rs:6:30
|
LL | const trait Unconditionally: const Super {}
| --------------- ^^^^^^^^^^^ ...because it cannot have a `const` supertrait
| |
| this trait is not dyn compatible...

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0038`.
Loading