Skip to content

Commit 89b6488

Browse files
Deny RPITIT for object safety
1 parent 1463688 commit 89b6488

File tree

4 files changed

+107
-0
lines changed

4 files changed

+107
-0
lines changed

compiler/rustc_middle/src/traits/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,12 @@ impl ObjectSafetyViolation {
908908
ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfOutput, _) => {
909909
format!("method `{}` references the `Self` type in its return type", name).into()
910910
}
911+
ObjectSafetyViolation::Method(
912+
name,
913+
MethodViolationCode::ReferencesImplTraitInTrait,
914+
_,
915+
) => format!("method `{}` references an `impl Trait` type in its return type", name)
916+
.into(),
911917
ObjectSafetyViolation::Method(
912918
name,
913919
MethodViolationCode::WhereClauseReferencesSelf,
@@ -1014,6 +1020,9 @@ pub enum MethodViolationCode {
10141020
/// e.g., `fn foo(&self) -> Self`
10151021
ReferencesSelfOutput,
10161022

1023+
/// e.g., `fn foo(&self) -> impl Sized`
1024+
ReferencesImplTraitInTrait,
1025+
10171026
/// e.g., `fn foo(&self) where Self: Clone`
10181027
WhereClauseReferencesSelf,
10191028

compiler/rustc_trait_selection/src/traits/object_safety.rs

+26
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use super::elaborate_predicates;
1313
use crate::infer::TyCtxtInferExt;
1414
use crate::traits::query::evaluate_obligation::InferCtxtExt;
1515
use crate::traits::{self, Obligation, ObligationCause};
16+
use hir::def::DefKind;
1617
use rustc_errors::{FatalError, MultiSpan};
1718
use rustc_hir as hir;
1819
use rustc_hir::def_id::DefId;
@@ -431,6 +432,9 @@ fn virtual_call_violation_for_method<'tcx>(
431432
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) {
432433
return Some(MethodViolationCode::ReferencesSelfOutput);
433434
}
435+
if contains_illegal_impl_trait_in_trait(tcx, sig.output()) {
436+
return Some(MethodViolationCode::ReferencesImplTraitInTrait);
437+
}
434438

435439
// We can't monomorphize things like `fn foo<A>(...)`.
436440
let own_counts = tcx.generics_of(method.def_id).own_counts();
@@ -793,6 +797,12 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
793797
ControlFlow::CONTINUE
794798
}
795799
}
800+
ty::Projection(ref data)
801+
if self.tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder =>
802+
{
803+
// We'll deny these later in their own pass
804+
ControlFlow::CONTINUE
805+
}
796806
ty::Projection(ref data) => {
797807
// This is a projected type `<Foo as SomeTrait>::X`.
798808

@@ -861,6 +871,22 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
861871
.is_break()
862872
}
863873

874+
pub fn contains_illegal_impl_trait_in_trait<'tcx>(
875+
tcx: TyCtxt<'tcx>,
876+
ty: ty::Binder<'tcx, Ty<'tcx>>,
877+
) -> bool {
878+
// FIXME(RPITIT): Perhaps we should use a visitor here?
879+
ty.skip_binder().walk().any(|arg| {
880+
if let ty::GenericArgKind::Type(ty) = arg.unpack()
881+
&& let ty::Projection(proj) = ty.kind()
882+
{
883+
tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
884+
} else {
885+
false
886+
}
887+
})
888+
}
889+
864890
pub fn provide(providers: &mut ty::query::Providers) {
865891
*providers = ty::query::Providers { object_safety_violations, ..*providers };
866892
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#![feature(return_position_impl_trait_in_trait)]
2+
#![allow(incomplete_features)]
3+
4+
use std::fmt::Debug;
5+
6+
trait Foo {
7+
fn baz(&self) -> impl Debug;
8+
}
9+
10+
impl Foo for u32 {
11+
fn baz(&self) -> u32 {
12+
32
13+
}
14+
}
15+
16+
fn main() {
17+
let i = Box::new(42_u32) as Box<dyn Foo>;
18+
//~^ ERROR the trait `Foo` cannot be made into an object
19+
//~| ERROR the trait `Foo` cannot be made into an object
20+
let s = i.baz();
21+
//~^ ERROR the trait `Foo` cannot be made into an object
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
error[E0038]: the trait `Foo` cannot be made into an object
2+
--> $DIR/object-safety.rs:17:33
3+
|
4+
LL | let i = Box::new(42_u32) as Box<dyn Foo>;
5+
| ^^^^^^^^^^^^ `Foo` cannot be made into an object
6+
|
7+
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>
8+
--> $DIR/object-safety.rs:7:8
9+
|
10+
LL | trait Foo {
11+
| --- this trait cannot be made into an object...
12+
LL | fn baz(&self) -> impl Debug;
13+
| ^^^ ...because method `baz` references an `impl Trait` type in its return type
14+
= help: consider moving `baz` to another trait
15+
16+
error[E0038]: the trait `Foo` cannot be made into an object
17+
--> $DIR/object-safety.rs:20:13
18+
|
19+
LL | let s = i.baz();
20+
| ^^^^^^^ `Foo` cannot be made into an object
21+
|
22+
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>
23+
--> $DIR/object-safety.rs:7:8
24+
|
25+
LL | trait Foo {
26+
| --- this trait cannot be made into an object...
27+
LL | fn baz(&self) -> impl Debug;
28+
| ^^^ ...because method `baz` references an `impl Trait` type in its return type
29+
= help: consider moving `baz` to another trait
30+
31+
error[E0038]: the trait `Foo` cannot be made into an object
32+
--> $DIR/object-safety.rs:17:13
33+
|
34+
LL | let i = Box::new(42_u32) as Box<dyn Foo>;
35+
| ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
36+
|
37+
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>
38+
--> $DIR/object-safety.rs:7:8
39+
|
40+
LL | trait Foo {
41+
| --- this trait cannot be made into an object...
42+
LL | fn baz(&self) -> impl Debug;
43+
| ^^^ ...because method `baz` references an `impl Trait` type in its return type
44+
= help: consider moving `baz` to another trait
45+
= note: required for `Box<u32>` to implement `CoerceUnsized<Box<dyn Foo>>`
46+
= note: required by cast to type `Box<dyn Foo>`
47+
48+
error: aborting due to 3 previous errors
49+
50+
For more information about this error, try `rustc --explain E0038`.

0 commit comments

Comments
 (0)