implement raw-pointer self. Works for traits, including trait objects, but not structs
This commit is contained in:
parent
53a6d14e5b
commit
361b3db886
6 changed files with 130 additions and 18 deletions
|
|
@ -59,9 +59,7 @@ impl ObjectSafetyViolation {
|
|||
ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
|
||||
format!("method `{}` has generic type parameters", name).into(),
|
||||
ObjectSafetyViolation::Method(name, MethodViolationCode::NonStandardSelfType) =>
|
||||
format!("method `{}` has a non-standard `self` type. Only `&self`, \
|
||||
`&mut self`, and `Box<Self>` are currently supported \
|
||||
for trait objects", name).into(),
|
||||
format!("method `{}` has a non-standard `self` type", name).into(),
|
||||
ObjectSafetyViolation::AssociatedConst(name) =>
|
||||
format!("the trait cannot contain associated consts like `{}`", name).into(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1191,6 +1191,7 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
pub enum ExplicitSelf<'tcx> {
|
||||
ByValue,
|
||||
ByReference(ty::Region<'tcx>, hir::Mutability),
|
||||
ByRawPointer(hir::Mutability),
|
||||
ByBox,
|
||||
Other
|
||||
}
|
||||
|
|
@ -1231,10 +1232,15 @@ impl<'tcx> ExplicitSelf<'tcx> {
|
|||
|
||||
match self_arg_ty.sty {
|
||||
_ if is_self_ty(self_arg_ty) => ByValue,
|
||||
ty::TyRef(region, ty::TypeAndMut { ty, mutbl}) if is_self_ty(ty) => {
|
||||
ty::TyRef(region, ty::TypeAndMut { ty, mutbl }) if is_self_ty(ty) => {
|
||||
ByReference(region, mutbl)
|
||||
}
|
||||
ty::TyAdt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => ByBox,
|
||||
ty::TyRawPtr(ty::TypeAndMut { ty, mutbl }) if is_self_ty(ty) => {
|
||||
ByRawPointer(mutbl)
|
||||
}
|
||||
ty::TyAdt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => {
|
||||
ByBox
|
||||
}
|
||||
_ => Other
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
|||
cur_ty: Ty<'tcx>,
|
||||
obligations: Vec<traits::PredicateObligation<'tcx>>,
|
||||
at_start: bool,
|
||||
include_raw_pointers: bool,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
|
|
@ -76,12 +77,13 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
// Otherwise, deref if type is derefable:
|
||||
let (kind, new_ty) = if let Some(mt) = self.cur_ty.builtin_deref(false, NoPreference) {
|
||||
(AutoderefKind::Builtin, mt.ty)
|
||||
} else {
|
||||
let ty = self.overloaded_deref_ty(self.cur_ty)?;
|
||||
(AutoderefKind::Overloaded, ty)
|
||||
};
|
||||
let (kind, new_ty) =
|
||||
if let Some(mt) = self.cur_ty.builtin_deref(self.include_raw_pointers, NoPreference) {
|
||||
(AutoderefKind::Builtin, mt.ty)
|
||||
} else {
|
||||
let ty = self.overloaded_deref_ty(self.cur_ty)?;
|
||||
(AutoderefKind::Overloaded, ty)
|
||||
};
|
||||
|
||||
if new_ty.references_error() {
|
||||
return None;
|
||||
|
|
@ -194,6 +196,15 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// also dereference through raw pointer types
|
||||
/// e.g. assuming ptr_to_Foo is the type `*const Foo`
|
||||
/// fcx.autoderef(span, ptr_to_Foo) => [*const Foo]
|
||||
/// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo]
|
||||
pub fn include_raw_pointers(mut self) -> Self {
|
||||
self.include_raw_pointers = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn finalize(self) {
|
||||
let fcx = self.fcx;
|
||||
fcx.register_predicates(self.into_obligations());
|
||||
|
|
@ -212,6 +223,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
cur_ty: self.resolve_type_vars_if_possible(&base_ty),
|
||||
obligations: vec![],
|
||||
at_start: true,
|
||||
include_raw_pointers: false,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -503,7 +503,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
|
|||
&ty::Binder(self_arg_ty)
|
||||
);
|
||||
|
||||
let mut autoderef = fcx.autoderef(span, self_arg_ty);
|
||||
let mut autoderef = fcx.autoderef(span, self_arg_ty).include_raw_pointers();
|
||||
|
||||
loop {
|
||||
if let Some((potential_self_ty, _)) = autoderef.next() {
|
||||
|
|
@ -532,12 +532,25 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
|
|||
let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
|
||||
let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty);
|
||||
|
||||
if let ExplicitSelf::Other = self_kind {
|
||||
if !fcx.tcx.sess.features.borrow().arbitrary_self_types {
|
||||
feature_gate::feature_err(&fcx.tcx.sess.parse_sess, "arbitrary_self_types", span,
|
||||
GateIssue::Language, "arbitrary `self` types are unstable")
|
||||
.help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
|
||||
.emit();
|
||||
if !fcx.tcx.sess.features.borrow().arbitrary_self_types {
|
||||
match self_kind {
|
||||
ExplicitSelf::ByValue |
|
||||
ExplicitSelf::ByReference(_, _) |
|
||||
ExplicitSelf::ByBox => (),
|
||||
|
||||
ExplicitSelf::ByRawPointer(_) => {
|
||||
feature_gate::feature_err(&fcx.tcx.sess.parse_sess, "arbitrary_self_types", span,
|
||||
GateIssue::Language, "raw pointer `self` is unstable")
|
||||
.help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
|
||||
.emit();
|
||||
}
|
||||
|
||||
ExplicitSelf::Other => {
|
||||
feature_gate::feature_err(&fcx.tcx.sess.parse_sess, "arbitrary_self_types", span,
|
||||
GateIssue::Language, "arbitrary `self` types are unstable")
|
||||
.help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
24
src/test/run-pass/arbitrary_self_types_raw_pointer_struct.rs
Normal file
24
src/test/run-pass/arbitrary_self_types_raw_pointer_struct.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// 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.
|
||||
|
||||
#![feature(arbitrary_self_types)]
|
||||
|
||||
struct Foo(String);
|
||||
|
||||
impl Foo {
|
||||
unsafe fn foo(self: *const Self) -> *const str {
|
||||
(*self).0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let foo = Foo("abc123".into());
|
||||
assert_eq!("abc123", unsafe { &*(&foo as *const Foo).foo() });
|
||||
}
|
||||
59
src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs
Normal file
59
src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// 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.
|
||||
|
||||
#![feature(arbitrary_self_types)]
|
||||
|
||||
use std::ptr;
|
||||
|
||||
trait Foo {
|
||||
fn foo(self: *const Self) -> &'static str;
|
||||
|
||||
unsafe fn bar(self: *const Self) -> i64;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
fn foo(self: *const Self) -> &'static str {
|
||||
"I'm an i32!"
|
||||
}
|
||||
|
||||
unsafe fn bar(self: *const Self) -> i64 {
|
||||
*self as i64
|
||||
}
|
||||
}
|
||||
|
||||
impl Foo for u32 {
|
||||
fn foo(self: *const Self) -> &'static str {
|
||||
"I'm a u32!"
|
||||
}
|
||||
|
||||
unsafe fn bar(self: *const Self) -> i64 {
|
||||
*self as i64
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let foo_i32 = ptr::null::<i32>() as *const Foo;
|
||||
let foo_u32 = ptr::null::<u32>() as *const Foo;
|
||||
|
||||
assert_eq!("I'm an i32!", foo_i32.foo());
|
||||
assert_eq!("I'm a u32!", foo_u32.foo());
|
||||
|
||||
let bar_i32 = 5i32;
|
||||
let bar_i32_thin = &bar_i32 as *const i32;
|
||||
assert_eq!(5, unsafe { bar_i32_thin.bar() });
|
||||
let bar_i32_fat = bar_i32_thin as *const Foo;
|
||||
assert_eq!(5, unsafe { bar_i32_fat.bar() });
|
||||
|
||||
let bar_u32 = 18u32;
|
||||
let bar_u32_thin = &bar_u32 as *const u32;
|
||||
assert_eq!(18, unsafe { bar_u32_thin.bar() });
|
||||
let bar_u32_fat = bar_u32_thin as *const Foo;
|
||||
assert_eq!(18, unsafe { bar_u32_fat.bar() });
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue