about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-12-19 07:05:05 +0000
committerbors <bors@rust-lang.org>2017-12-19 07:05:05 +0000
commita9f047c048eac4f135dd6df5223b7195d651539d (patch)
tree6aafdf5c1ae3526fa5cd6ff1e072b4dfe355a443
parentc8b94c6aa1bdee2fb6371e3f445f0abbba7c5093 (diff)
parent5c656f0c72d4a1aeff9a761fe455e522e975eee2 (diff)
downloadrust-a9f047c048eac4f135dd6df5223b7195d651539d.tar.gz
rust-a9f047c048eac4f135dd6df5223b7195d651539d.zip
Auto merge of #46664 - mikeyhew:raw_pointer_self, r=arielb1
arbitrary_self_types: add support for raw pointer `self` types

This adds support for raw pointer `self` types, under the `arbitrary_self_types` feature flag. Types like `self: *const Self`, `self: *const Rc<Self>`, `self: Rc<*const Self` are all supported. Object safety checks are updated to allow`self: *const Self` and `self: *mut Self`.

This PR does not add support for `*const self` and `*mut self` syntax. That can be added in a later PR once this code is reviewed and merged.

#44874

r? @arielb1
-rw-r--r--src/librustc/traits/object_safety.rs4
-rw-r--r--src/librustc/ty/util.rs10
-rw-r--r--src/librustc_typeck/check/autoderef.rs24
-rw-r--r--src/librustc_typeck/check/method/confirm.rs1
-rw-r--r--src/librustc_typeck/check/method/probe.rs42
-rw-r--r--src/librustc_typeck/check/wfcheck.rs34
-rw-r--r--src/test/run-pass/arbitrary_self_types_raw_pointer_struct.rs37
-rw-r--r--src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs70
-rw-r--r--src/test/ui/arbitrary-self-types-not-object-safe.stderr4
-rw-r--r--src/test/ui/feature-gate-arbitrary_self_types-raw-pointer.rs28
-rw-r--r--src/test/ui/feature-gate-arbitrary_self_types-raw-pointer.stderr29
-rw-r--r--src/test/ui/inference-variable-behind-raw-pointer.rs (renamed from src/test/compile-fail/issue-26194.rs)15
-rw-r--r--src/test/ui/inference-variable-behind-raw-pointer.stderr8
13 files changed, 273 insertions, 33 deletions
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index facd6350e19..4151661b593 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<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(),
         }
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 2e9e45c9ffe..46bc54b7f6a 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 d075bf43679..7832db7dcb5 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<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,
         }
     }
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 17ed0aaa30b..3a9c4e1901d 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)),
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 81e5b2fe00a..fe30ffb3cfc 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<Vec<CandidateStep<'tcx>>> {
         // 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();
 
@@ -307,9 +321,20 @@ 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
+                    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
+                    }
                 } else {
                     // If we're just looking for suggestions,
                     // though, ambiguity is no big thing, we can
@@ -322,6 +347,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 +858,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(|| {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index d4625bb58c3..e65ae6a1b4d 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,32 @@ 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();
+                }
             }
         }
     }
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 00000000000..8b6941e1c63
--- /dev/null
+++ b/src/test/run-pass/arbitrary_self_types_raw_pointer_struct.rs
@@ -0,0 +1,37 @@
+// 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::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<Self>) -> &'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::<Rc<Foo>>().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
new file mode 100644
index 00000000000..f70e38a14e4
--- /dev/null
+++ b/src/test/run-pass/arbitrary_self_types_raw_pointer_trait.rs
@@ -0,0 +1,70 @@
+// 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;
+
+    unsafe fn complicated(self: *const *const Self) -> i64 where Self: Sized {
+        (*self).bar()
+    }
+}
+
+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 null_i32 = ptr::null::<i32>() as *const Foo;
+    let null_u32 = ptr::null::<u32>() as *const Foo;
+
+    assert_eq!("I'm an i32!", null_i32.foo());
+    assert_eq!("I'm a u32!", null_u32.foo());
+
+    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 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() });
+
+}
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 a1090fe031e..f258488ee2f 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<Foo>;
    |                                 ^^^^^^^^ the trait `Foo` cannot be made into an object
    |
-   = note: method `foo` has a non-standard `self` type. Only `&self`, `&mut self`, and `Box<Self>` 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<Foo>;
    |             ^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
    |
-   = note: method `foo` has a non-standard `self` type. Only `&self`, `&mut self`, and `Box<Self>` 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<std::boxed::Box<Foo>>` for `std::boxed::Box<usize>`
 
 error: aborting due to 2 previous errors
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 00000000000..29e51727edc
--- /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 <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.
+
+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 00000000000..d629ac4c60f
--- /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<Self>`
+
+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<Self>`
+
+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<Self>`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/compile-fail/issue-26194.rs b/src/test/ui/inference-variable-behind-raw-pointer.rs
index 7ddd56229ce..0ae027679fe 100644
--- a/src/test/compile-fail/issue-26194.rs
+++ b/src/test/ui/inference-variable-behind-raw-pointer.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,11 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-struct S(String);
+// must-compile-successfully
 
-impl S {
-    fn f(self: *mut S) -> String { self.0 }
-    //~^ ERROR invalid `self` type
-}
+// tests that the following code compiles, but produces a future-compatibility warning
 
-fn main() { S("".to_owned()).f(); }
+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 00000000000..a8874c9bf5a
--- /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:18:13
+   |
+18 |     if data.is_null() {}
+   |             ^^^^^^^
+   |
+   = note: this will be made into a hard error in a future version of the compiler
+