Skip to content

Commit 361b3db

Browse files
committed
implement raw-pointer self. Works for traits, including trait objects, but not structs
1 parent 53a6d14 commit 361b3db

File tree

6 files changed

+130
-18
lines changed

6 files changed

+130
-18
lines changed

src/librustc/traits/object_safety.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,7 @@ impl ObjectSafetyViolation {
5959
ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
6060
format!("method `{}` has generic type parameters", name).into(),
6161
ObjectSafetyViolation::Method(name, MethodViolationCode::NonStandardSelfType) =>
62-
format!("method `{}` has a non-standard `self` type. Only `&self`, \
63-
`&mut self`, and `Box<Self>` are currently supported \
64-
for trait objects", name).into(),
62+
format!("method `{}` has a non-standard `self` type", name).into(),
6563
ObjectSafetyViolation::AssociatedConst(name) =>
6664
format!("the trait cannot contain associated consts like `{}`", name).into(),
6765
}

src/librustc/ty/util.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,7 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
11911191
pub enum ExplicitSelf<'tcx> {
11921192
ByValue,
11931193
ByReference(ty::Region<'tcx>, hir::Mutability),
1194+
ByRawPointer(hir::Mutability),
11941195
ByBox,
11951196
Other
11961197
}
@@ -1231,10 +1232,15 @@ impl<'tcx> ExplicitSelf<'tcx> {
12311232

12321233
match self_arg_ty.sty {
12331234
_ if is_self_ty(self_arg_ty) => ByValue,
1234-
ty::TyRef(region, ty::TypeAndMut { ty, mutbl}) if is_self_ty(ty) => {
1235+
ty::TyRef(region, ty::TypeAndMut { ty, mutbl }) if is_self_ty(ty) => {
12351236
ByReference(region, mutbl)
12361237
}
1237-
ty::TyAdt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => ByBox,
1238+
ty::TyRawPtr(ty::TypeAndMut { ty, mutbl }) if is_self_ty(ty) => {
1239+
ByRawPointer(mutbl)
1240+
}
1241+
ty::TyAdt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => {
1242+
ByBox
1243+
}
12381244
_ => Other
12391245
}
12401246
}

src/librustc_typeck/check/autoderef.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> {
3737
cur_ty: Ty<'tcx>,
3838
obligations: Vec<traits::PredicateObligation<'tcx>>,
3939
at_start: bool,
40+
include_raw_pointers: bool,
4041
span: Span,
4142
}
4243

@@ -76,12 +77,13 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
7677
}
7778

7879
// Otherwise, deref if type is derefable:
79-
let (kind, new_ty) = if let Some(mt) = self.cur_ty.builtin_deref(false, NoPreference) {
80-
(AutoderefKind::Builtin, mt.ty)
81-
} else {
82-
let ty = self.overloaded_deref_ty(self.cur_ty)?;
83-
(AutoderefKind::Overloaded, ty)
84-
};
80+
let (kind, new_ty) =
81+
if let Some(mt) = self.cur_ty.builtin_deref(self.include_raw_pointers, NoPreference) {
82+
(AutoderefKind::Builtin, mt.ty)
83+
} else {
84+
let ty = self.overloaded_deref_ty(self.cur_ty)?;
85+
(AutoderefKind::Overloaded, ty)
86+
};
8587

8688
if new_ty.references_error() {
8789
return None;
@@ -194,6 +196,15 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
194196
}
195197
}
196198

199+
/// also dereference through raw pointer types
200+
/// e.g. assuming ptr_to_Foo is the type `*const Foo`
201+
/// fcx.autoderef(span, ptr_to_Foo) => [*const Foo]
202+
/// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo]
203+
pub fn include_raw_pointers(mut self) -> Self {
204+
self.include_raw_pointers = true;
205+
self
206+
}
207+
197208
pub fn finalize(self) {
198209
let fcx = self.fcx;
199210
fcx.register_predicates(self.into_obligations());
@@ -212,6 +223,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
212223
cur_ty: self.resolve_type_vars_if_possible(&base_ty),
213224
obligations: vec![],
214225
at_start: true,
226+
include_raw_pointers: false,
215227
span,
216228
}
217229
}

src/librustc_typeck/check/wfcheck.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
503503
&ty::Binder(self_arg_ty)
504504
);
505505

506-
let mut autoderef = fcx.autoderef(span, self_arg_ty);
506+
let mut autoderef = fcx.autoderef(span, self_arg_ty).include_raw_pointers();
507507

508508
loop {
509509
if let Some((potential_self_ty, _)) = autoderef.next() {
@@ -532,12 +532,25 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
532532
let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
533533
let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty);
534534

535-
if let ExplicitSelf::Other = self_kind {
536-
if !fcx.tcx.sess.features.borrow().arbitrary_self_types {
537-
feature_gate::feature_err(&fcx.tcx.sess.parse_sess, "arbitrary_self_types", span,
538-
GateIssue::Language, "arbitrary `self` types are unstable")
539-
.help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
540-
.emit();
535+
if !fcx.tcx.sess.features.borrow().arbitrary_self_types {
536+
match self_kind {
537+
ExplicitSelf::ByValue |
538+
ExplicitSelf::ByReference(_, _) |
539+
ExplicitSelf::ByBox => (),
540+
541+
ExplicitSelf::ByRawPointer(_) => {
542+
feature_gate::feature_err(&fcx.tcx.sess.parse_sess, "arbitrary_self_types", span,
543+
GateIssue::Language, "raw pointer `self` is unstable")
544+
.help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
545+
.emit();
546+
}
547+
548+
ExplicitSelf::Other => {
549+
feature_gate::feature_err(&fcx.tcx.sess.parse_sess, "arbitrary_self_types", span,
550+
GateIssue::Language, "arbitrary `self` types are unstable")
551+
.help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
552+
.emit();
553+
}
541554
}
542555
}
543556
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(arbitrary_self_types)]
12+
13+
struct Foo(String);
14+
15+
impl Foo {
16+
unsafe fn foo(self: *const Self) -> *const str {
17+
(*self).0.as_ref()
18+
}
19+
}
20+
21+
fn main() {
22+
let foo = Foo("abc123".into());
23+
assert_eq!("abc123", unsafe { &*(&foo as *const Foo).foo() });
24+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(arbitrary_self_types)]
12+
13+
use std::ptr;
14+
15+
trait Foo {
16+
fn foo(self: *const Self) -> &'static str;
17+
18+
unsafe fn bar(self: *const Self) -> i64;
19+
}
20+
21+
impl Foo for i32 {
22+
fn foo(self: *const Self) -> &'static str {
23+
"I'm an i32!"
24+
}
25+
26+
unsafe fn bar(self: *const Self) -> i64 {
27+
*self as i64
28+
}
29+
}
30+
31+
impl Foo for u32 {
32+
fn foo(self: *const Self) -> &'static str {
33+
"I'm a u32!"
34+
}
35+
36+
unsafe fn bar(self: *const Self) -> i64 {
37+
*self as i64
38+
}
39+
}
40+
41+
fn main() {
42+
let foo_i32 = ptr::null::<i32>() as *const Foo;
43+
let foo_u32 = ptr::null::<u32>() as *const Foo;
44+
45+
assert_eq!("I'm an i32!", foo_i32.foo());
46+
assert_eq!("I'm a u32!", foo_u32.foo());
47+
48+
let bar_i32 = 5i32;
49+
let bar_i32_thin = &bar_i32 as *const i32;
50+
assert_eq!(5, unsafe { bar_i32_thin.bar() });
51+
let bar_i32_fat = bar_i32_thin as *const Foo;
52+
assert_eq!(5, unsafe { bar_i32_fat.bar() });
53+
54+
let bar_u32 = 18u32;
55+
let bar_u32_thin = &bar_u32 as *const u32;
56+
assert_eq!(18, unsafe { bar_u32_thin.bar() });
57+
let bar_u32_fat = bar_u32_thin as *const Foo;
58+
assert_eq!(18, unsafe { bar_u32_fat.bar() });
59+
}

0 commit comments

Comments
 (0)