From 361b3db886c6f63c57c11e036b01bb8b09f35739 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 9 Nov 2017 16:15:35 -0500 Subject: [PATCH 01/14] implement raw-pointer `self`. Works for traits, including trait objects, but not structs --- src/librustc/traits/object_safety.rs | 4 +- src/librustc/ty/util.rs | 10 +++- src/librustc_typeck/check/autoderef.rs | 24 ++++++-- src/librustc_typeck/check/wfcheck.rs | 27 ++++++--- ...arbitrary_self_types_raw_pointer_struct.rs | 24 ++++++++ .../arbitrary_self_types_raw_pointer_trait.rs | 59 +++++++++++++++++++ 6 files changed, 130 insertions(+), 18 deletions(-) create mode 100644 src/test/run-pass/arbitrary_self_types_raw_pointer_struct.rs create mode 100644 src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index facd6350e196c..4151661b5933c 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -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` 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(), } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 2e9e45c9ffe16..46bc54b7f6a67 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -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 } } diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index d075bf4367920..7832db7dcb542 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -37,6 +37,7 @@ pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> { cur_ty: Ty<'tcx>, obligations: Vec>, 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, } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index d4625bb58c338..5cb6c6a368e14 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -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`") - .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`") + .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`") + .emit(); + } } } } diff --git a/src/test/run-pass/arbitrary_self_types_raw_pointer_struct.rs b/src/test/run-pass/arbitrary_self_types_raw_pointer_struct.rs new file mode 100644 index 0000000000000..e213d33a9c2de --- /dev/null +++ b/src/test/run-pass/arbitrary_self_types_raw_pointer_struct.rs @@ -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 or the MIT license +// , 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() }); +} diff --git a/src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs b/src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs new file mode 100644 index 0000000000000..0d64dacaf4e7c --- /dev/null +++ b/src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs @@ -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 or the MIT license +// , 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::() as *const Foo; + let foo_u32 = ptr::null::() 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() }); +} From 083635eab2c146a35d734ab40c5a3ba5df720786 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Fri, 10 Nov 2017 07:52:30 -0500 Subject: [PATCH 02/14] changed some stuff in probe.rs and it broke libstd --- src/librustc_typeck/check/method/probe.rs | 25 ++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 81e5b2fe00a6a..19fb32f96dffb 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -77,6 +77,12 @@ impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> { struct CandidateStep<'tcx> { self_ty: Ty<'tcx>, autoderefs: usize, + // true if the type results from a dereference of a raw pointer. + // when assembling candidates, we include these steps, but not when + // picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods + // `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then + // `foo.by_raw_ptr()` will work and `foo.by_ref()` won't. + from_unsafe_deref: bool, unsize: bool, } @@ -257,6 +263,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { vec![CandidateStep { self_ty, autoderefs: 0, + from_unsafe_deref: false, unsize: false, }] }; @@ -289,14 +296,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -> Option>> { // FIXME: we don't need to create the entire steps in one pass - let mut autoderef = self.autoderef(span, self_ty); + let mut autoderef = self.autoderef(span, self_ty).include_raw_pointers(); + let mut reached_raw_pointer = false; let mut steps: Vec<_> = autoderef.by_ref() .map(|(ty, d)| { - CandidateStep { + let step = CandidateStep { self_ty: ty, autoderefs: d, + from_unsafe_deref: reached_raw_pointer, unsize: false, + }; + if let ty::TyRawPtr(_) = ty.sty { + // all the subsequent steps will be from_unsafe_deref + reached_raw_pointer = true; } + step }) .collect(); @@ -322,6 +336,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { steps.push(CandidateStep { self_ty: self.tcx.mk_slice(elem_ty), autoderefs: dereferences, + // this could be from an unsafe deref if we had + // a *mut/const [T; N] + from_unsafe_deref: reached_raw_pointer, unsize: true, }); } @@ -830,7 +847,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { .iter() .filter(|step| { debug!("pick_core: step={:?}", step); - !step.self_ty.references_error() + // skip types that are from a type error or that would require dereferencing + // a raw pointer + !step.self_ty.references_error() && !step.from_unsafe_deref }).flat_map(|step| { self.pick_by_value_method(step).or_else(|| { self.pick_autorefd_method(step, hir::MutImmutable).or_else(|| { From e7d1542a52dd04b58058d5d170a7a9b09f528f8c Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Fri, 10 Nov 2017 10:30:30 -0500 Subject: [PATCH 03/14] don't emit a type error if autoderef ends in an inference variable, as long as we went through a raw pointer This avoids a break in backward compatibility in the following case: ``` let ptr = std::ptr::null(); let _ = &data as *const *const (); if data.null() {} ``` --- src/librustc_typeck/check/method/probe.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 19fb32f96dffb..141f0eea1fbe5 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -321,9 +321,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // a real method lookup, this is a hard error (it's an // ambiguity and we can't make progress). if !is_suggestion.0 { - let t = self.structurally_resolved_type(span, final_ty); - assert_eq!(t, self.tcx.types.err); - return None + // don't report a type error if we dereferenced a raw pointer, + // because that would break backwards compatibility in certain cases + if !reached_raw_pointer { + let t = self.structurally_resolved_type(span, final_ty); + assert_eq!(t, self.tcx.types.err); + return None + } } else { // If we're just looking for suggestions, // though, ambiguity is no big thing, we can From bff74fbfe2eccc3a1cf2f0e0823cca342e3b9cd1 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 11 Dec 2017 02:27:40 +0100 Subject: [PATCH 04/14] shorten lines for tidy --- src/librustc_typeck/check/wfcheck.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 5cb6c6a368e14..e65ae6a1b4db3 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -539,15 +539,22 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { ExplicitSelf::ByBox => (), ExplicitSelf::ByRawPointer(_) => { - feature_gate::feature_err(&fcx.tcx.sess.parse_sess, "arbitrary_self_types", span, - GateIssue::Language, "raw pointer `self` is unstable") + 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`") .emit(); } ExplicitSelf::Other => { - feature_gate::feature_err(&fcx.tcx.sess.parse_sess, "arbitrary_self_types", span, - GateIssue::Language, "arbitrary `self` types are unstable") + 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`") .emit(); } From cb9f552b7c1b2e7a13d4d8419e39ed186a26c80d Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 11 Dec 2017 18:14:47 +0100 Subject: [PATCH 05/14] Add a feature_gate test for raw pointer self --- ...e-gate-arbitrary_self_types-raw-pointer.rs | 28 ++++++++++++++++++ ...te-arbitrary_self_types-raw-pointer.stderr | 29 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/test/ui/feature-gate-arbitrary_self_types-raw-pointer.rs create mode 100644 src/test/ui/feature-gate-arbitrary_self_types-raw-pointer.stderr diff --git a/src/test/ui/feature-gate-arbitrary_self_types-raw-pointer.rs b/src/test/ui/feature-gate-arbitrary_self_types-raw-pointer.rs new file mode 100644 index 0000000000000..29e51727edcfd --- /dev/null +++ b/src/test/ui/feature-gate-arbitrary_self_types-raw-pointer.rs @@ -0,0 +1,28 @@ +// Copyright 2017 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. + +struct Foo; + +impl Foo { + fn foo(self: *const Self) {} + //~^ ERROR raw pointer `self` is unstable +} + +trait Bar { + fn bar(self: *const Self); + //~^ ERROR raw pointer `self` is unstable +} + +impl Bar for () { + fn bar(self: *const Self) {} + //~^ ERROR raw pointer `self` is unstable +} + +fn main() {} diff --git a/src/test/ui/feature-gate-arbitrary_self_types-raw-pointer.stderr b/src/test/ui/feature-gate-arbitrary_self_types-raw-pointer.stderr new file mode 100644 index 0000000000000..d629ac4c60fc0 --- /dev/null +++ b/src/test/ui/feature-gate-arbitrary_self_types-raw-pointer.stderr @@ -0,0 +1,29 @@ +error: raw pointer `self` is unstable (see issue #44874) + --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:19:18 + | +19 | fn bar(self: *const Self); + | ^^^^^^^^^^^ + | + = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable + = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` + +error: raw pointer `self` is unstable (see issue #44874) + --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:14:18 + | +14 | fn foo(self: *const Self) {} + | ^^^^^^^^^^^ + | + = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable + = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` + +error: raw pointer `self` is unstable (see issue #44874) + --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:24:18 + | +24 | fn bar(self: *const Self) {} + | ^^^^^^^^^^^ + | + = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable + = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` + +error: aborting due to 3 previous errors + From 8aac984e408272cb3bd40c7cdda41c4842b7edad Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 11 Dec 2017 18:17:50 +0100 Subject: [PATCH 06/14] Fix ICE in probe::confirm::extract_existential_trait_ref with raw pointer self --- src/librustc_typeck/check/method/confirm.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 17ed0aaa30b02..3a9c4e1901d27 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -276,6 +276,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // FIXME: this feels, like, super dubious self.fcx .autoderef(self.span, self_ty) + .include_raw_pointers() .filter_map(|(ty, _)| { match ty.sty { ty::TyDynamic(ref data, ..) => data.principal().map(|p| closure(self, ty, p)), From c5fc7c52930f304785deef66738caed0f9df9ba9 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 11 Dec 2017 18:18:44 +0100 Subject: [PATCH 07/14] update error message in test/compile-fail/issue-26194.rs --- src/test/compile-fail/issue-26194.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/issue-26194.rs b/src/test/compile-fail/issue-26194.rs index 7ddd56229ceb7..3936055552d17 100644 --- a/src/test/compile-fail/issue-26194.rs +++ b/src/test/compile-fail/issue-26194.rs @@ -12,7 +12,7 @@ struct S(String); impl S { fn f(self: *mut S) -> String { self.0 } - //~^ ERROR invalid `self` type + //~^ ERROR raw pointer `self` is unstable } fn main() { S("".to_owned()).f(); } From 428b0259b66f4a52b9e61d780a6decc7c049fa64 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 11 Dec 2017 18:48:06 +0100 Subject: [PATCH 08/14] remove test for issue #26194 because it is now redundant --- src/test/compile-fail/issue-26194.rs | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 src/test/compile-fail/issue-26194.rs diff --git a/src/test/compile-fail/issue-26194.rs b/src/test/compile-fail/issue-26194.rs deleted file mode 100644 index 3936055552d17..0000000000000 --- a/src/test/compile-fail/issue-26194.rs +++ /dev/null @@ -1,18 +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. - -struct S(String); - -impl S { - fn f(self: *mut S) -> String { self.0 } - //~^ ERROR raw pointer `self` is unstable -} - -fn main() { S("".to_owned()).f(); } From bc0439b3880808e1385da4b99964d5d506f76e3f Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 14 Dec 2017 18:42:40 +0100 Subject: [PATCH 09/14] Warn about inference variables behind raw pointers in method lookup --- src/librustc_typeck/check/method/probe.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 141f0eea1fbe5..fe30ffb3cfccd 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -321,9 +321,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // a real method lookup, this is a hard error (it's an // ambiguity and we can't make progress). if !is_suggestion.0 { - // don't report a type error if we dereferenced a raw pointer, - // because that would break backwards compatibility in certain cases - if !reached_raw_pointer { + if reached_raw_pointer + && !self.tcx.sess.features.borrow().arbitrary_self_types { + // only produce a warning in this case, because inference variables used to + // be allowed here in some cases for raw pointers + struct_span_warn!(self.tcx.sess, span, E0619, + "the type of this value must be known in this context") + .note("this will be made into a hard error in a future version of \ + the compiler") + .emit(); + } else { let t = self.structurally_resolved_type(span, final_ty); assert_eq!(t, self.tcx.types.err); return None From 4cae2c087d0bfb336ae13a71b55034c4ff2e0acd Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 14 Dec 2017 18:43:27 +0100 Subject: [PATCH 10/14] Add tests with *const Rc and similar self types --- ...arbitrary_self_types_raw_pointer_struct.rs | 13 +++++++++++++ .../arbitrary_self_types_raw_pointer_trait.rs | 19 +++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/test/run-pass/arbitrary_self_types_raw_pointer_struct.rs b/src/test/run-pass/arbitrary_self_types_raw_pointer_struct.rs index e213d33a9c2de..8b6941e1c635c 100644 --- a/src/test/run-pass/arbitrary_self_types_raw_pointer_struct.rs +++ b/src/test/run-pass/arbitrary_self_types_raw_pointer_struct.rs @@ -10,15 +10,28 @@ #![feature(arbitrary_self_types)] +use std::rc::Rc; + struct Foo(String); impl Foo { unsafe fn foo(self: *const Self) -> *const str { (*self).0.as_ref() } + + fn complicated_1(self: *const Rc) -> &'static str { + "Foo::complicated_1" + } + + unsafe fn complicated_2(self: Rc<*const Self>) -> *const str { + (**self).0.as_ref() + } } fn main() { let foo = Foo("abc123".into()); assert_eq!("abc123", unsafe { &*(&foo as *const Foo).foo() }); + assert_eq!("Foo::complicated_1", std::ptr::null::>().complicated_1()); + let rc = Rc::new(&foo as *const Foo); + assert_eq!("abc123", unsafe { &*rc.complicated_2()}); } diff --git a/src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs b/src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs index 0d64dacaf4e7c..15b65d1127812 100644 --- a/src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs +++ b/src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs @@ -16,6 +16,10 @@ trait Foo { fn foo(self: *const Self) -> &'static str; unsafe fn bar(self: *const Self) -> i64; + + unsafe fn complicated(self: *const *const Self) -> i64 where Self: Sized { + (*self).bar() + } } impl Foo for i32 { @@ -39,21 +43,28 @@ impl Foo for u32 { } fn main() { - let foo_i32 = ptr::null::() as *const Foo; - let foo_u32 = ptr::null::() as *const Foo; + let null_i32 = ptr::null::() as *const Foo; + let null_u32 = ptr::null::() as *const Foo; - assert_eq!("I'm an i32!", foo_i32.foo()); - assert_eq!("I'm a u32!", foo_u32.foo()); + assert_eq!("I'm an i32!", null_i32.foo()); + assert_eq!("I'm a u32!", null_u32.foo()); let bar_i32 = 5i32; let bar_i32_thin = &bar_i32 as *const i32; + assert_eq!("I'm an i32!", bar_i32_thin.foo()); assert_eq!(5, unsafe { bar_i32_thin.bar() }); + assert_eq!(5, unsafe { (&bar_i32_thin as *const *const i32).complicated() }); let bar_i32_fat = bar_i32_thin as *const Foo; + assert_eq!("I'm an i32!", bar_i32_fat.foo()); assert_eq!(5, unsafe { bar_i32_fat.bar() }); let bar_u32 = 18u32; let bar_u32_thin = &bar_u32 as *const u32; + assert_eq!("I'm a u32!", bar_u32_thin.foo()); assert_eq!(18, unsafe { bar_u32_thin.bar() }); + assert_eq!(18, unsafe { (&bar_u32_thin as *const *const u32).complicated() }); let bar_u32_fat = bar_u32_thin as *const Foo; + assert_eq!("I'm a u32!", bar_u32_fat.foo()); assert_eq!(18, unsafe { bar_u32_fat.bar() }); + } From 0cc573a9eea1a3f96e85c58a1acd586175d98796 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 14 Dec 2017 18:44:28 +0100 Subject: [PATCH 11/14] better variable names in tests --- .../arbitrary_self_types_raw_pointer_trait.rs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs b/src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs index 15b65d1127812..f70e38a14e416 100644 --- a/src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs +++ b/src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs @@ -49,22 +49,22 @@ fn main() { assert_eq!("I'm an i32!", null_i32.foo()); assert_eq!("I'm a u32!", null_u32.foo()); - let bar_i32 = 5i32; - let bar_i32_thin = &bar_i32 as *const i32; - assert_eq!("I'm an i32!", bar_i32_thin.foo()); - assert_eq!(5, unsafe { bar_i32_thin.bar() }); - assert_eq!(5, unsafe { (&bar_i32_thin as *const *const i32).complicated() }); - let bar_i32_fat = bar_i32_thin as *const Foo; - assert_eq!("I'm an i32!", bar_i32_fat.foo()); - assert_eq!(5, unsafe { bar_i32_fat.bar() }); + let valid_i32 = 5i32; + let valid_i32_thin = &valid_i32 as *const i32; + assert_eq!("I'm an i32!", valid_i32_thin.foo()); + assert_eq!(5, unsafe { valid_i32_thin.bar() }); + assert_eq!(5, unsafe { (&valid_i32_thin as *const *const i32).complicated() }); + let valid_i32_fat = valid_i32_thin as *const Foo; + assert_eq!("I'm an i32!", valid_i32_fat.foo()); + assert_eq!(5, unsafe { valid_i32_fat.bar() }); - let bar_u32 = 18u32; - let bar_u32_thin = &bar_u32 as *const u32; - assert_eq!("I'm a u32!", bar_u32_thin.foo()); - assert_eq!(18, unsafe { bar_u32_thin.bar() }); - assert_eq!(18, unsafe { (&bar_u32_thin as *const *const u32).complicated() }); - let bar_u32_fat = bar_u32_thin as *const Foo; - assert_eq!("I'm a u32!", bar_u32_fat.foo()); - assert_eq!(18, unsafe { bar_u32_fat.bar() }); + let valid_u32 = 18u32; + let valid_u32_thin = &valid_u32 as *const u32; + assert_eq!("I'm a u32!", valid_u32_thin.foo()); + assert_eq!(18, unsafe { valid_u32_thin.bar() }); + assert_eq!(18, unsafe { (&valid_u32_thin as *const *const u32).complicated() }); + let valid_u32_fat = valid_u32_thin as *const Foo; + assert_eq!("I'm a u32!", valid_u32_fat.foo()); + assert_eq!(18, unsafe { valid_u32_fat.bar() }); } From 63ce99c6f8a8dcbe9b739989362aac527202c110 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 14 Dec 2017 18:51:25 +0100 Subject: [PATCH 12/14] add a ui test for the inference variable warning --- .../ui/inference-variable-behind-raw-pointer.rs | 15 +++++++++++++++ .../inference-variable-behind-raw-pointer.stderr | 8 ++++++++ 2 files changed, 23 insertions(+) create mode 100644 src/test/ui/inference-variable-behind-raw-pointer.rs create mode 100644 src/test/ui/inference-variable-behind-raw-pointer.stderr diff --git a/src/test/ui/inference-variable-behind-raw-pointer.rs b/src/test/ui/inference-variable-behind-raw-pointer.rs new file mode 100644 index 0000000000000..f2065ae6a1ace --- /dev/null +++ b/src/test/ui/inference-variable-behind-raw-pointer.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +fn main() { + let data = std::ptr::null(); + let _ = &data as *const *const (); + if data.is_null() {} +} diff --git a/src/test/ui/inference-variable-behind-raw-pointer.stderr b/src/test/ui/inference-variable-behind-raw-pointer.stderr new file mode 100644 index 0000000000000..b0aa21cf5f5f0 --- /dev/null +++ b/src/test/ui/inference-variable-behind-raw-pointer.stderr @@ -0,0 +1,8 @@ +warning[E0619]: the type of this value must be known in this context + --> $DIR/inference-variable-behind-raw-pointer.rs:14:13 + | +14 | if data.is_null() {} + | ^^^^^^^ + | + = note: this will be made into a hard error in a future version of the compiler + From 23555b9f127a787fc649f869a0d39317ea30d681 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Fri, 15 Dec 2017 08:20:54 +0100 Subject: [PATCH 13/14] fix ui test had to tell the test suite that it's supposed to compile --- src/test/ui/inference-variable-behind-raw-pointer.rs | 4 ++++ src/test/ui/inference-variable-behind-raw-pointer.stderr | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/ui/inference-variable-behind-raw-pointer.rs b/src/test/ui/inference-variable-behind-raw-pointer.rs index f2065ae6a1ace..0ae027679fe31 100644 --- a/src/test/ui/inference-variable-behind-raw-pointer.rs +++ b/src/test/ui/inference-variable-behind-raw-pointer.rs @@ -8,6 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// must-compile-successfully + +// tests that the following code compiles, but produces a future-compatibility warning + fn main() { let data = std::ptr::null(); let _ = &data as *const *const (); diff --git a/src/test/ui/inference-variable-behind-raw-pointer.stderr b/src/test/ui/inference-variable-behind-raw-pointer.stderr index b0aa21cf5f5f0..a8874c9bf5a39 100644 --- a/src/test/ui/inference-variable-behind-raw-pointer.stderr +++ b/src/test/ui/inference-variable-behind-raw-pointer.stderr @@ -1,7 +1,7 @@ warning[E0619]: the type of this value must be known in this context - --> $DIR/inference-variable-behind-raw-pointer.rs:14:13 + --> $DIR/inference-variable-behind-raw-pointer.rs:18:13 | -14 | if data.is_null() {} +18 | if data.is_null() {} | ^^^^^^^ | = note: this will be made into a hard error in a future version of the compiler From 5c656f0c72d4a1aeff9a761fe455e522e975eee2 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 17 Dec 2017 10:16:41 +0100 Subject: [PATCH 14/14] update ui/arbitrary-self-types-not-object-safe with shorter error message --- src/test/ui/arbitrary-self-types-not-object-safe.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/arbitrary-self-types-not-object-safe.stderr b/src/test/ui/arbitrary-self-types-not-object-safe.stderr index a1090fe031eb9..f258488ee2fb1 100644 --- a/src/test/ui/arbitrary-self-types-not-object-safe.stderr +++ b/src/test/ui/arbitrary-self-types-not-object-safe.stderr @@ -4,7 +4,7 @@ error[E0038]: the trait `Foo` cannot be made into an object 40 | let x = Box::new(5usize) as Box; | ^^^^^^^^ the trait `Foo` cannot be made into an object | - = note: method `foo` has a non-standard `self` type. Only `&self`, `&mut self`, and `Box` are currently supported for trait objects + = note: method `foo` has a non-standard `self` type error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/arbitrary-self-types-not-object-safe.rs:40:13 @@ -12,7 +12,7 @@ error[E0038]: the trait `Foo` cannot be made into an object 40 | let x = Box::new(5usize) as Box; | ^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | - = note: method `foo` has a non-standard `self` type. Only `&self`, `&mut self`, and `Box` are currently supported for trait objects + = note: method `foo` has a non-standard `self` type = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` error: aborting due to 2 previous errors