Traits that reference `Self` in the supertrait list are not object-safe. Fixes #22040.
This commit is contained in:
parent
02e1d5ec06
commit
ff388c1277
|
@ -20,7 +20,7 @@
|
||||||
use super::supertraits;
|
use super::supertraits;
|
||||||
use super::elaborate_predicates;
|
use super::elaborate_predicates;
|
||||||
|
|
||||||
use middle::subst::{self, SelfSpace};
|
use middle::subst::{self, SelfSpace, TypeSpace};
|
||||||
use middle::traits;
|
use middle::traits;
|
||||||
use middle::ty::{self, Ty};
|
use middle::ty::{self, Ty};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -31,6 +31,10 @@ pub enum ObjectSafetyViolation<'tcx> {
|
||||||
/// Self : Sized declared on the trait
|
/// Self : Sized declared on the trait
|
||||||
SizedSelf,
|
SizedSelf,
|
||||||
|
|
||||||
|
/// Supertrait reference references `Self` an in illegal location
|
||||||
|
/// (e.g. `trait Foo : Bar<Self>`)
|
||||||
|
SupertraitSelf,
|
||||||
|
|
||||||
/// Method has something illegal
|
/// Method has something illegal
|
||||||
Method(Rc<ty::Method<'tcx>>, MethodViolationCode),
|
Method(Rc<ty::Method<'tcx>>, MethodViolationCode),
|
||||||
}
|
}
|
||||||
|
@ -110,6 +114,9 @@ fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
if trait_has_sized_self(tcx, trait_def_id) {
|
if trait_has_sized_self(tcx, trait_def_id) {
|
||||||
violations.push(ObjectSafetyViolation::SizedSelf);
|
violations.push(ObjectSafetyViolation::SizedSelf);
|
||||||
}
|
}
|
||||||
|
if supertraits_reference_self(tcx, trait_def_id) {
|
||||||
|
violations.push(ObjectSafetyViolation::SupertraitSelf);
|
||||||
|
}
|
||||||
|
|
||||||
debug!("object_safety_violations_for_trait(trait_def_id={}) = {}",
|
debug!("object_safety_violations_for_trait(trait_def_id={}) = {}",
|
||||||
trait_def_id.repr(tcx),
|
trait_def_id.repr(tcx),
|
||||||
|
@ -118,6 +125,34 @@ fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
violations
|
violations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
|
trait_def_id: ast::DefId)
|
||||||
|
-> bool
|
||||||
|
{
|
||||||
|
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
|
||||||
|
let trait_ref = trait_def.trait_ref.clone();
|
||||||
|
let predicates = ty::predicates_for_trait_ref(tcx, &ty::Binder(trait_ref));
|
||||||
|
predicates
|
||||||
|
.into_iter()
|
||||||
|
.any(|predicate| {
|
||||||
|
match predicate {
|
||||||
|
ty::Predicate::Trait(ref data) => {
|
||||||
|
// In the case of a trait predicate, we can skip the "self" type.
|
||||||
|
data.0.trait_ref.substs.types.get_slice(TypeSpace)
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.any(is_self)
|
||||||
|
}
|
||||||
|
ty::Predicate::Projection(..) |
|
||||||
|
ty::Predicate::TypeOutlives(..) |
|
||||||
|
ty::Predicate::RegionOutlives(..) |
|
||||||
|
ty::Predicate::Equate(..) => {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
|
fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
trait_def_id: ast::DefId)
|
trait_def_id: ast::DefId)
|
||||||
-> bool
|
-> bool
|
||||||
|
@ -138,11 +173,7 @@ fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
.any(|predicate| {
|
.any(|predicate| {
|
||||||
match predicate {
|
match predicate {
|
||||||
ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
|
ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
|
||||||
let self_ty = trait_pred.0.self_ty();
|
is_self(trait_pred.0.self_ty())
|
||||||
match self_ty.sty {
|
|
||||||
ty::ty_param(ref data) => data.space == subst::SelfSpace,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ty::Predicate::Projection(..) |
|
ty::Predicate::Projection(..) |
|
||||||
ty::Predicate::Trait(..) |
|
ty::Predicate::Trait(..) |
|
||||||
|
@ -295,8 +326,17 @@ impl<'tcx> Repr<'tcx> for ObjectSafetyViolation<'tcx> {
|
||||||
match *self {
|
match *self {
|
||||||
ObjectSafetyViolation::SizedSelf =>
|
ObjectSafetyViolation::SizedSelf =>
|
||||||
format!("SizedSelf"),
|
format!("SizedSelf"),
|
||||||
|
ObjectSafetyViolation::SupertraitSelf =>
|
||||||
|
format!("SupertraitSelf"),
|
||||||
ObjectSafetyViolation::Method(ref m, code) =>
|
ObjectSafetyViolation::Method(ref m, code) =>
|
||||||
format!("Method({},{:?})", m.repr(tcx), code),
|
format!("Method({},{:?})", m.repr(tcx), code),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_self<'tcx>(ty: Ty<'tcx>) -> bool {
|
||||||
|
match ty.sty {
|
||||||
|
ty::ty_param(ref data) => data.space == subst::SelfSpace,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ use std::marker;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops;
|
use std::ops;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::vec::CowVec;
|
use std::vec::{CowVec, IntoIter};
|
||||||
use collections::enum_set::{EnumSet, CLike};
|
use collections::enum_set::{EnumSet, CLike};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use syntax::abi;
|
use syntax::abi;
|
||||||
|
@ -2034,6 +2034,40 @@ impl<'tcx> AsPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Predicate<'tcx> {
|
impl<'tcx> Predicate<'tcx> {
|
||||||
|
/// Iterates over the types in this predicate. Note that in all
|
||||||
|
/// cases this is skipping over a binder, so late-bound regions
|
||||||
|
/// with depth 0 are bound by the predicate.
|
||||||
|
pub fn walk_tys(&self) -> IntoIter<Ty<'tcx>> {
|
||||||
|
let vec: Vec<_> = match *self {
|
||||||
|
ty::Predicate::Trait(ref data) => {
|
||||||
|
data.0.trait_ref.substs.types.as_slice().to_vec()
|
||||||
|
}
|
||||||
|
ty::Predicate::Equate(ty::Binder(ref data)) => {
|
||||||
|
vec![data.0, data.1]
|
||||||
|
}
|
||||||
|
ty::Predicate::TypeOutlives(ty::Binder(ref data)) => {
|
||||||
|
vec![data.0]
|
||||||
|
}
|
||||||
|
ty::Predicate::RegionOutlives(..) => {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
ty::Predicate::Projection(ref data) => {
|
||||||
|
let trait_inputs = data.0.projection_ty.trait_ref.substs.types.as_slice();
|
||||||
|
trait_inputs.iter()
|
||||||
|
.cloned()
|
||||||
|
.chain(Some(data.0.ty).into_iter())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// The only reason to collect into a vector here is that I was
|
||||||
|
// too lazy to make the full (somewhat complicated) iterator
|
||||||
|
// type that would be needed here. But I wanted this fn to
|
||||||
|
// return an iterator conceptually, rather than a `Vec`, so as
|
||||||
|
// to be closer to `Ty::walk`.
|
||||||
|
vec.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn has_escaping_regions(&self) -> bool {
|
pub fn has_escaping_regions(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Predicate::Trait(ref trait_ref) => trait_ref.has_escaping_regions(),
|
Predicate::Trait(ref trait_ref) => trait_ref.has_escaping_regions(),
|
||||||
|
|
|
@ -126,6 +126,13 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
"the trait cannot require that `Self : Sized`");
|
"the trait cannot require that `Self : Sized`");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObjectSafetyViolation::SupertraitSelf => {
|
||||||
|
tcx.sess.span_note(
|
||||||
|
span,
|
||||||
|
"the trait cannot use `Self` as a type parameter \
|
||||||
|
in the supertrait listing");
|
||||||
|
}
|
||||||
|
|
||||||
ObjectSafetyViolation::Method(method, MethodViolationCode::ByValueSelf) => {
|
ObjectSafetyViolation::Method(method, MethodViolationCode::ByValueSelf) => {
|
||||||
tcx.sess.span_note(
|
tcx.sess.span_note(
|
||||||
span,
|
span,
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
// 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 <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.
|
||||||
|
|
||||||
|
// Regression test for #22040.
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
trait Expr: Debug + PartialEq {
|
||||||
|
fn print_element_count(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
//#[derive(PartialEq)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct SExpr<'x> {
|
||||||
|
elements: Vec<Box<Expr+ 'x>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'x> PartialEq for SExpr<'x> {
|
||||||
|
fn eq(&self, other:&SExpr<'x>) -> bool {
|
||||||
|
println!("L1: {} L2: {}", self.elements.len(), other.elements.len());
|
||||||
|
let result = self.elements.len() == other.elements.len();
|
||||||
|
|
||||||
|
println!("Got compare {}", result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'x> SExpr<'x> {
|
||||||
|
fn new() -> SExpr<'x> { return SExpr{elements: Vec::new(),}; }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'x> Expr for SExpr<'x> {
|
||||||
|
fn print_element_count(&self) {
|
||||||
|
println!("element count: {}", self.elements.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a: Box<Expr> = Box::new(SExpr::new()); //~ ERROR trait `Expr` is not object-safe
|
||||||
|
let b: Box<Expr> = Box::new(SExpr::new()); //~ ERROR trait `Expr` is not object-safe
|
||||||
|
|
||||||
|
assert_eq!(a , b);
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// Check that we correctly prevent users from making trait objects
|
||||||
|
// form traits that make use of `Self` in an argument or return position.
|
||||||
|
|
||||||
|
trait Bar<T> {
|
||||||
|
fn bar(&self, x: &T);
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Baz : Bar<Self> {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_bar<T:Bar<u32>>(t: &T) -> &Bar<u32> {
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_baz<T:Baz>(t: &T) -> &Baz {
|
||||||
|
t
|
||||||
|
//~^ ERROR `Baz` is not object-safe
|
||||||
|
//~| NOTE the trait cannot use `Self` as a type parameter in the supertrait listing
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
Loading…
Reference in New Issue