提交 361b3db8 编写于 作者: M Michael Hewson

implement raw-pointer `self`. Works for traits, including trait objects, but not structs

上级 53a6d14e
......@@ -59,9 +59,7 @@ pub fn error_msg(&self) -> Cow<'static, str> {
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 @@ pub fn determine<P>(
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 @@ fn next(&mut self) -> Option<Self::Item> {
}
// 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 @@ pub fn adjust_steps_as_infer_ok(&self, pref: LvaluePreference)
}
}
/// 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 @@ pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx,
cur_ty: self.resolve_type_vars_if_possible(&base_ty),
obligations: vec![],
at_start: true,
include_raw_pointers: false,
span,
}
}
......
......@@ -503,7 +503,7 @@ fn check_method_receiver<'fcx, 'tcx>(&mut self,
&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 @@ fn check_method_receiver<'fcx, 'tcx>(&mut self,
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();
}
}
}
}
......
// 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() });
}
// 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() });
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册