Skip to content

Commit

Permalink
Self in where clauses may not be object safe
Browse files Browse the repository at this point in the history
This is virtually certain to cause regressions, needs crater.

In #50781 it was discovered that our object safety rules are not sound because we allow `Self` in where clauses without restrain. This PR is a direct fix to the rules so that we disallow methods with unsound where clauses.

This currently uses hard error to measure impact, but we will want to downgrade it to a future compat error.

Fixes #50781.

r? @nikomatsakis
  • Loading branch information
leoyvens committed Jun 25, 2018
1 parent 5f9c7f9 commit 1453b3a
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 37 deletions.
11 changes: 11 additions & 0 deletions src/librustc/traits/object_safety.rs
Expand Up @@ -288,6 +288,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
return Some(MethodViolationCode::Generic);
}

if self.predicates_of(method.def_id).predicates.into_iter()
// A trait object can't claim to live more than the concrete type,
// so outlives predicates will always hold.
.filter(|p| p.to_opt_type_outlives().is_none())
.collect::<Vec<_>>()
// Do a shallow visit so that `contains_illegal_self_type_reference`
// may apply it's custom visiting.
.visit_tys_shallow(|t| self.contains_illegal_self_type_reference(trait_def_id, t)) {
return Some(MethodViolationCode::ReferencesSelf);
}

None
}

Expand Down
14 changes: 14 additions & 0 deletions src/librustc/ty/fold.rs
Expand Up @@ -136,6 +136,20 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
fn has_late_bound_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
}

/// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`.
fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> bool) -> bool {

pub struct Visitor<F>(F);

impl<'tcx, F: FnMut(Ty<'tcx>) -> bool> TypeVisitor<'tcx> for Visitor<F> {
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
self.0(ty)
}
}

self.visit_with(&mut Visitor(visit))
}
}

/// The TypeFolder trait defines the actual *folding*. There is a
Expand Down
37 changes: 0 additions & 37 deletions src/test/run-pass/issue-23435.rs

This file was deleted.

27 changes: 27 additions & 0 deletions src/test/ui/issue-50781.rs
@@ -0,0 +1,27 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

trait Trait {}

trait X {
fn foo(&self) where Self: Trait;
}

impl X for () {
fn foo(&self) {}
}

impl Trait for dyn X {}
//~^ ERROR the trait `X` cannot be made into an object

pub fn main() {
// Check that this does not segfault.
<X as X>::foo(&());
}
11 changes: 11 additions & 0 deletions src/test/ui/issue-50781.stderr
@@ -0,0 +1,11 @@
error[E0038]: the trait `X` cannot be made into an object
--> $DIR/issue-50781.rs:21:6
|
LL | impl Trait for dyn X {}
| ^^^^^ the trait `X` cannot be made into an object
|
= note: method `foo` references the `Self` type in its arguments or return type

error: aborting due to previous error

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

0 comments on commit 1453b3a

Please sign in to comment.