Skip to content
Open
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
31 changes: 31 additions & 0 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use super::{
SelectionError, specialization_graph, translate_args, util,
};
use crate::diagnostics::InherentProjectionNormalizationOverflow;
use crate::error_reporting::traits::report_dyn_incompatibility;
use crate::infer::{BoundRegionConversionTime, InferOk};
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
Expand Down Expand Up @@ -712,6 +713,35 @@ fn project<'cx, 'tcx>(
)));
}

// `<dyn Trait>::Name` is only valid when `Trait` is dyn-compatible.
// If it isn't, create an error at the projection site and return a tainted error term.
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
if let ty::Dynamic(data, ..) = self_ty.kind() {
if let Some(def_id) = data.principal_def_id() {
let tcx = selcx.tcx();
if !tcx.is_dyn_compatible(def_id) {
let span = obligation.cause.span;
let guar = if !span.is_dummy() {
let violations = tcx.dyn_compatibility_violations(def_id);
report_dyn_incompatibility(tcx, span, None, def_id, &violations).emit()
} else {
tcx.dcx().span_delayed_bug(
span,
format!(
"projection from non-dyn-compatible trait `{}`",
tcx.def_path_str(def_id)
),
)
};
return Ok(Projected::Progress(Progress::error_for_term(
tcx,
obligation.predicate,
guar,
)));
}
}
}

let mut candidates = ProjectionCandidateSet::None;

// Make sure that the following procedures are kept in order. ParamEnv
Expand Down Expand Up @@ -856,6 +886,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
}
_ => return,
};

let env_predicates = data
.projection_bounds()
.filter(|bound| bound.item_def_id() == obligation.predicate.expect_projection_def_id())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ trait Foo: Deref<Target = W> {
fn test(x: &dyn Foo) {
//~^ ERROR the trait `Foo` is not dyn compatible
x.method();
//~^ ERROR the trait `Foo` is not dyn compatible
}

fn main() {}
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,7 @@ LL | fn method(self: &W) {}
= note: type of `self` must be `Self` or a type that dereferences to it
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)

error[E0038]: the trait `Foo` is not dyn compatible
--> $DIR/dispatch-dyn-incompatible-that-does-not-deref.rs:14:5
|
LL | fn method(self: &W) {}
| -- help: consider changing method `method`'s `self` parameter to be `&self`: `&Self`
...
LL | x.method();
| ^^^^^^^^^^ `Foo` 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/dispatch-dyn-incompatible-that-does-not-deref.rs:8:21
|
LL | trait Foo: Deref<Target = W> {
| --- this trait is not dyn compatible...
LL | fn method(self: &W) {}
| ^^ ...because method `method`'s `self` parameter cannot be dispatched on

error: aborting due to 3 previous errors
error: aborting due to 2 previous errors

Some errors have detailed explanations: E0038, E0307.
For more information about an error, try `rustc --explain E0038`.
1 change: 1 addition & 0 deletions tests/ui/traits/ice-with-dyn-pointee-errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ fn raw_pointer_in(x: &dyn Pointee<Metadata = ()>) {
//~^ ERROR the trait `Pointee` is not dyn compatible
unknown_sized_object_ptr_in(x)
//~^ ERROR the trait `Pointee` is not dyn compatible
//~| ERROR the trait `Pointee` is not dyn compatible
}

fn main() {
Expand Down
16 changes: 14 additions & 2 deletions tests/ui/traits/ice-with-dyn-pointee-errors.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ note: for a trait to be dyn compatible it needs to allow building a vtable
|
= note: the trait is not dyn compatible because it opted out of dyn-compatibility

error[E0038]: the trait `Pointee` is not dyn compatible
--> $DIR/ice-with-dyn-pointee-errors.rs:10:5
|
LL | unknown_sized_object_ptr_in(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Pointee` 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>
--> $SRC_DIR/core/src/ptr/metadata.rs:LL:COL
|
= note: the trait is not dyn compatible because it opted out of dyn-compatibility

error[E0038]: the trait `Pointee` is not dyn compatible
--> $DIR/ice-with-dyn-pointee-errors.rs:10:5
|
Expand All @@ -23,7 +35,7 @@ note: for a trait to be dyn compatible it needs to allow building a vtable
= note: the trait is not dyn compatible because it opted out of dyn-compatibility

error[E0038]: the trait `Pointee` is not dyn compatible
--> $DIR/ice-with-dyn-pointee-errors.rs:15:20
--> $DIR/ice-with-dyn-pointee-errors.rs:16:20
|
LL | raw_pointer_in(&42)
| ^^^ `Pointee` is not dyn compatible
Expand All @@ -34,6 +46,6 @@ note: for a trait to be dyn compatible it needs to allow building a vtable
|
= note: the trait is not dyn compatible because it opted out of dyn-compatibility

error: aborting due to 3 previous errors
error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0038`.
20 changes: 20 additions & 0 deletions tests/ui/traits/object/dyn-proj-non-dyn-compat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Check that we are not producing long error messages

trait Trait {
type Output;
fn process<T>(&mut self, input: T) -> T;
}

struct MyImpl;

impl Trait for MyImpl {
type Output = &'static str;
fn process<T>(&mut self, input: T) -> T { input }
}

fn make() -> impl Trait<Output = <dyn Trait<Output = &'static str> as Trait>::Output> {
//~^ ERROR the trait `Trait` is not dyn compatible
MyImpl
}

fn main() {}
21 changes: 21 additions & 0 deletions tests/ui/traits/object/dyn-proj-non-dyn-compat.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0038]: the trait `Trait` is not dyn compatible
--> $DIR/dyn-proj-non-dyn-compat.rs:15:14
|
LL | fn make() -> impl Trait<Output = <dyn Trait<Output = &'static str> as Trait>::Output> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Trait` 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/dyn-proj-non-dyn-compat.rs:5:8
|
LL | trait Trait {
| ----- this trait is not dyn compatible...
LL | type Output;
LL | fn process<T>(&mut self, input: T) -> T;
| ^^^^^^^ ...because method `process` has generic type parameters
= help: consider moving `process` to another trait
= help: only type `MyImpl` implements `Trait`; consider using it directly instead.

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0038`.
13 changes: 13 additions & 0 deletions tests/ui/traits/object/dyn-type-param-bound-not-checked.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//@ check-pass
// Protection against a naive fix for #152607

//@ revisions: current next

//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver

trait Trait<T: Sized> {}

fn foo(_: &dyn Trait<[u32]>) {}

fn main() {}
Loading