Skip to content

Commit

Permalink
Check WhereClauseReferencesSelf after all other object safety checks
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Oct 7, 2022
1 parent 0ca3565 commit 4143194
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 13 deletions.
28 changes: 15 additions & 13 deletions compiler/rustc_trait_selection/src/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,19 +447,6 @@ fn virtual_call_violation_for_method<'tcx>(
return Some(MethodViolationCode::Generic);
}

if tcx
.predicates_of(method.def_id)
.predicates
.iter()
// A trait object can't claim to live more than the concrete type,
// so outlives predicates will always hold.
.cloned()
.filter(|(p, _)| p.to_opt_type_outlives().is_none())
.any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred))
{
return Some(MethodViolationCode::WhereClauseReferencesSelf);
}

let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));

// Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
Expand Down Expand Up @@ -538,6 +525,21 @@ fn virtual_call_violation_for_method<'tcx>(
}
}

// NOTE: This check happens last, because it results in a lint, and not a
// hard error.
if tcx
.predicates_of(method.def_id)
.predicates
.iter()
// A trait object can't claim to live more than the concrete type,
// so outlives predicates will always hold.
.cloned()
.filter(|(p, _)| p.to_opt_type_outlives().is_none())
.any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred))
{
return Some(MethodViolationCode::WhereClauseReferencesSelf);
}

None
}

Expand Down
26 changes: 26 additions & 0 deletions src/test/ui/object-safety/issue-102762.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// compile-flags: --crate-type=lib
// This test checks that the `where_clauses_object_safety` lint does not cause
// other object safety *hard errors* to be suppressed, because we currently
// only emit one object safety error per trait...

use std::future::Future;
use std::pin::Pin;

pub trait Fetcher: Send + Sync {
fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
where
Self: Sync,
{
todo!()
}
}

fn fetcher() -> Box<dyn Fetcher> {
//~^ ERROR the trait `Fetcher` cannot be made into an object
todo!()
}

pub fn foo() {
let fetcher = fetcher();
let _ = fetcher.get();
}
20 changes: 20 additions & 0 deletions src/test/ui/object-safety/issue-102762.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0038]: the trait `Fetcher` cannot be made into an object
--> $DIR/issue-102762.rs:18:21
|
LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
| ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self`
...
LL | fn fetcher() -> Box<dyn Fetcher> {
| ^^^^^^^^^^^ `Fetcher` cannot be made into an object
|
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>
--> $DIR/issue-102762.rs:10:22
|
LL | pub trait Fetcher: Send + Sync {
| ------- this trait cannot be made into an object...
LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>>
| ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on

error: aborting due to previous error

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

0 comments on commit 4143194

Please sign in to comment.