From 1453b3a67dfe73329e07c17cd07b55bd71d7350b Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Tue, 22 May 2018 12:09:35 -0300 Subject: [PATCH] `Self` in where clauses may not be object safe 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 --- src/librustc/traits/object_safety.rs | 11 +++++++++ src/librustc/ty/fold.rs | 14 +++++++++++ src/test/run-pass/issue-23435.rs | 37 ---------------------------- src/test/ui/issue-50781.rs | 27 ++++++++++++++++++++ src/test/ui/issue-50781.stderr | 11 +++++++++ 5 files changed, 63 insertions(+), 37 deletions(-) delete mode 100644 src/test/run-pass/issue-23435.rs create mode 100644 src/test/ui/issue-50781.rs create mode 100644 src/test/ui/issue-50781.stderr diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 6c67c10dc69cf..9dc1f06fc1133 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -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::>() + // 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 } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index d459a6de0d69e..307e1b238386c 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -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); + + impl<'tcx, F: FnMut(Ty<'tcx>) -> bool> TypeVisitor<'tcx> for Visitor { + 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 diff --git a/src/test/run-pass/issue-23435.rs b/src/test/run-pass/issue-23435.rs deleted file mode 100644 index 9b727826e6dc7..0000000000000 --- a/src/test/run-pass/issue-23435.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that we do not ICE when a default method implementation has -// requirements (in this case, `Self : Baz`) that do not hold for some -// specific impl (in this case, `Foo : Bar`). This causes problems -// only when building a vtable, because that goes along and -// instantiates all the methods, even those that could not otherwise -// be called. - -// pretty-expanded FIXME #23616 - -struct Foo { - x: i32 -} - -trait Bar { - fn bar(&self) where Self : Baz { self.baz(); } -} - -trait Baz { - fn baz(&self); -} - -impl Bar for Foo { -} - -fn main() { - let x: &Bar = &Foo { x: 22 }; -} diff --git a/src/test/ui/issue-50781.rs b/src/test/ui/issue-50781.rs new file mode 100644 index 0000000000000..3974fd54cf62b --- /dev/null +++ b/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 or the MIT license +// , 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. + ::foo(&()); +} diff --git a/src/test/ui/issue-50781.stderr b/src/test/ui/issue-50781.stderr new file mode 100644 index 0000000000000..34d7303a9a544 --- /dev/null +++ b/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`.