Skip to content

Commit 0ef4da1

Browse files
authored
Rollup merge of #108842 - compiler-errors:non_lifetime_binders-object-safe, r=b-naber
Enforce non-lifetime-binders in supertrait preds are not object safe We can't construct vtables for these supertraits.
2 parents 82dc127 + 720cc40 commit 0ef4da1

File tree

4 files changed

+111
-3
lines changed

4 files changed

+111
-3
lines changed

compiler/rustc_middle/src/traits/mod.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,9 @@ pub enum ObjectSafetyViolation {
897897
/// (e.g., `trait Foo : Bar<Self>`).
898898
SupertraitSelf(SmallVec<[Span; 1]>),
899899

900+
// Supertrait has a non-lifetime `for<T>` binder.
901+
SupertraitNonLifetimeBinder(SmallVec<[Span; 1]>),
902+
900903
/// Method has something illegal.
901904
Method(Symbol, MethodViolationCode, Span),
902905

@@ -919,6 +922,9 @@ impl ObjectSafetyViolation {
919922
.into()
920923
}
921924
}
925+
ObjectSafetyViolation::SupertraitNonLifetimeBinder(_) => {
926+
format!("where clause cannot reference non-lifetime `for<...>` variables").into()
927+
}
922928
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
923929
format!("associated function `{}` has no `self` parameter", name).into()
924930
}
@@ -969,7 +975,9 @@ impl ObjectSafetyViolation {
969975

970976
pub fn solution(&self, err: &mut Diagnostic) {
971977
match self {
972-
ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {}
978+
ObjectSafetyViolation::SizedSelf(_)
979+
| ObjectSafetyViolation::SupertraitSelf(_)
980+
| ObjectSafetyViolation::SupertraitNonLifetimeBinder(..) => {}
973981
ObjectSafetyViolation::Method(
974982
name,
975983
MethodViolationCode::StaticMethod(Some((add_self_sugg, make_sized_sugg))),
@@ -1023,7 +1031,8 @@ impl ObjectSafetyViolation {
10231031
// diagnostics use a `note` instead of a `span_label`.
10241032
match self {
10251033
ObjectSafetyViolation::SupertraitSelf(spans)
1026-
| ObjectSafetyViolation::SizedSelf(spans) => spans.clone(),
1034+
| ObjectSafetyViolation::SizedSelf(spans)
1035+
| ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans) => spans.clone(),
10271036
ObjectSafetyViolation::AssocConst(_, span)
10281037
| ObjectSafetyViolation::GAT(_, span)
10291038
| ObjectSafetyViolation::Method(_, _, span)

compiler/rustc_trait_selection/src/traits/object_safety.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ use rustc_errors::{DelayDm, FatalError, MultiSpan};
1717
use rustc_hir as hir;
1818
use rustc_hir::def_id::DefId;
1919
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
20-
use rustc_middle::ty::ToPredicate;
2120
use rustc_middle::ty::{
2221
self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
2322
};
23+
use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
2424
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
2525
use rustc_span::symbol::Symbol;
2626
use rustc_span::Span;
@@ -139,6 +139,10 @@ fn object_safety_violations_for_trait(
139139
if !spans.is_empty() {
140140
violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
141141
}
142+
let spans = super_predicates_have_non_lifetime_binders(tcx, trait_def_id);
143+
if !spans.is_empty() {
144+
violations.push(ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans));
145+
}
142146

143147
violations.extend(
144148
tcx.associated_items(trait_def_id)
@@ -348,6 +352,21 @@ fn predicate_references_self<'tcx>(
348352
}
349353
}
350354

355+
fn super_predicates_have_non_lifetime_binders(
356+
tcx: TyCtxt<'_>,
357+
trait_def_id: DefId,
358+
) -> SmallVec<[Span; 1]> {
359+
// If non_lifetime_binders is disabled, then exit early
360+
if !tcx.features().non_lifetime_binders {
361+
return SmallVec::new();
362+
}
363+
tcx.super_predicates_of(trait_def_id)
364+
.predicates
365+
.iter()
366+
.filter_map(|(pred, span)| pred.has_non_region_late_bound().then_some(*span))
367+
.collect()
368+
}
369+
351370
fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
352371
generics_require_sized_self(tcx, trait_def_id)
353372
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![feature(non_lifetime_binders)]
2+
//~^ WARN the feature `non_lifetime_binders` is incomplete
3+
4+
trait Foo: for<T> Bar<T> {}
5+
6+
trait Bar<T: ?Sized> {
7+
fn method(&self) {}
8+
}
9+
10+
fn needs_bar(x: &(impl Bar<i32> + ?Sized)) {
11+
x.method();
12+
}
13+
14+
impl Foo for () {}
15+
16+
impl<T: ?Sized> Bar<T> for () {}
17+
18+
fn main() {
19+
let x: &dyn Foo = &();
20+
//~^ ERROR the trait `Foo` cannot be made into an object
21+
//~| ERROR the trait `Foo` cannot be made into an object
22+
needs_bar(x);
23+
//~^ ERROR the trait `Foo` cannot be made into an object
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/supertrait-object-safety.rs:1:12
3+
|
4+
LL | #![feature(non_lifetime_binders)]
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error[E0038]: the trait `Foo` cannot be made into an object
11+
--> $DIR/supertrait-object-safety.rs:19:23
12+
|
13+
LL | let x: &dyn Foo = &();
14+
| ^^^ `Foo` cannot be made into an object
15+
|
16+
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
17+
--> $DIR/supertrait-object-safety.rs:4:12
18+
|
19+
LL | trait Foo: for<T> Bar<T> {}
20+
| --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables
21+
| |
22+
| this trait cannot be made into an object...
23+
= note: required for `&()` to implement `CoerceUnsized<&dyn Foo>`
24+
= note: required by cast to type `&dyn Foo`
25+
26+
error[E0038]: the trait `Foo` cannot be made into an object
27+
--> $DIR/supertrait-object-safety.rs:19:12
28+
|
29+
LL | let x: &dyn Foo = &();
30+
| ^^^^^^^^ `Foo` cannot be made into an object
31+
|
32+
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
33+
--> $DIR/supertrait-object-safety.rs:4:12
34+
|
35+
LL | trait Foo: for<T> Bar<T> {}
36+
| --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables
37+
| |
38+
| this trait cannot be made into an object...
39+
40+
error[E0038]: the trait `Foo` cannot be made into an object
41+
--> $DIR/supertrait-object-safety.rs:22:5
42+
|
43+
LL | needs_bar(x);
44+
| ^^^^^^^^^ `Foo` cannot be made into an object
45+
|
46+
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
47+
--> $DIR/supertrait-object-safety.rs:4:12
48+
|
49+
LL | trait Foo: for<T> Bar<T> {}
50+
| --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables
51+
| |
52+
| this trait cannot be made into an object...
53+
54+
error: aborting due to 3 previous errors; 1 warning emitted
55+
56+
For more information about this error, try `rustc --explain E0038`.

0 commit comments

Comments
 (0)