about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2019-02-24 12:54:45 +0000
committerMatthew Jasper <mjjasper1@gmail.com>2019-02-24 13:02:37 +0000
commit19a54e80934c802109ae7175cc824c22c672caa6 (patch)
tree11318a9d4faab744555a47457ce31eafe578ffcf
parent7d01aa8a4815207d83664353895ac168b7564e4b (diff)
Type check pointer comparisons
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs40
-rw-r--r--src/test/ui/nll/type-check-pointer-comparisons.rs33
-rw-r--r--src/test/ui/nll/type-check-pointer-comparisons.stderr62
3 files changed, 134 insertions, 1 deletions
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 6b948e40bfb..ef0f11ecfb9 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -27,6 +27,7 @@ use rustc::hir::def_id::DefId;
 use rustc::infer::canonical::QueryRegionConstraint;
 use rustc::infer::outlives::env::RegionBoundPairs;
 use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin};
+use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
 use rustc::mir::tcx::PlaceTy;
 use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
@@ -2103,7 +2104,44 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 self.add_reborrow_constraint(location, region, borrowed_place);
             }
 
-            // FIXME: These other cases have to be implemented in future PRs
+            Rvalue::BinaryOp(BinOp::Eq, left, right)
+            | Rvalue::BinaryOp(BinOp::Ne, left, right)
+            | Rvalue::BinaryOp(BinOp::Lt, left, right)
+            | Rvalue::BinaryOp(BinOp::Le, left, right)
+            | Rvalue::BinaryOp(BinOp::Gt, left, right)
+            | Rvalue::BinaryOp(BinOp::Ge, left, right) => {
+                let ty_left = left.ty(mir, tcx);
+                if let ty::RawPtr(_) | ty::FnPtr(_) = ty_left.sty {
+                    let ty_right = right.ty(mir, tcx);
+                    let common_ty = self.infcx.next_ty_var(
+                        TypeVariableOrigin::MiscVariable(mir.source_info(location).span),
+                    );
+                    self.sub_types(
+                        common_ty,
+                        ty_left,
+                        location.to_locations(),
+                        ConstraintCategory::Boring
+                    ).unwrap_or_else(|err| {
+                        bug!("Could not equate type variable with {:?}: {:?}", ty_left, err)
+                    });
+                    if let Err(terr) = self.sub_types(
+                        common_ty,
+                        ty_right,
+                        location.to_locations(),
+                        ConstraintCategory::Boring
+                    ) {
+                        span_mirbug!(
+                            self,
+                            rvalue,
+                            "unexpected comparison types {:?} and {:?} yields {:?}",
+                            ty_left,
+                            ty_right,
+                            terr
+                        )
+                    }
+                }
+            }
+
             Rvalue::Use(..)
             | Rvalue::Len(..)
             | Rvalue::BinaryOp(..)
diff --git a/src/test/ui/nll/type-check-pointer-comparisons.rs b/src/test/ui/nll/type-check-pointer-comparisons.rs
new file mode 100644
index 00000000000..3c900356fab
--- /dev/null
+++ b/src/test/ui/nll/type-check-pointer-comparisons.rs
@@ -0,0 +1,33 @@
+#![feature(nll)]
+
+// Check that we assert that pointers have a common subtype for comparisons
+
+fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) {
+    x == y;
+    //~^ ERROR lifetime may not live long enough
+    //~| ERROR lifetime may not live long enough
+}
+
+fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) {
+    x == y;
+    //~^ ERROR lifetime may not live long enough
+    //~| ERROR lifetime may not live long enough
+}
+
+fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32)) {
+    f == g;
+    //~^ ERROR lifetime may not live long enough
+    //~| ERROR lifetime may not live long enough
+}
+
+fn compare_hr_fn_ptr<'a>(f: fn(&'a i32), g: fn(&i32)) {
+    // Ideally this should compile with the operands swapped as well, but HIR
+    // type checking prevents it (and stops compilation) for now.
+    f == g; // OK
+}
+
+fn compare_const_fn_ptr<'a>(f: *const fn(&'a i32), g: *const fn(&i32)) {
+    f == g; // OK
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/type-check-pointer-comparisons.stderr b/src/test/ui/nll/type-check-pointer-comparisons.stderr
new file mode 100644
index 00000000000..c0a994cfb63
--- /dev/null
+++ b/src/test/ui/nll/type-check-pointer-comparisons.stderr
@@ -0,0 +1,62 @@
+error: lifetime may not live long enough
+  --> $DIR/type-check-pointer-comparisons.rs:6:5
+   |
+LL | fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) {
+   |                  --  -- lifetime `'b` defined here
+   |                  |
+   |                  lifetime `'a` defined here
+LL |     x == y;
+   |     ^ requires that `'a` must outlive `'b`
+
+error: lifetime may not live long enough
+  --> $DIR/type-check-pointer-comparisons.rs:6:10
+   |
+LL | fn compare_const<'a, 'b>(x: *const &mut &'a i32, y: *const &mut &'b i32) {
+   |                  --  -- lifetime `'b` defined here
+   |                  |
+   |                  lifetime `'a` defined here
+LL |     x == y;
+   |          ^ requires that `'b` must outlive `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/type-check-pointer-comparisons.rs:12:5
+   |
+LL | fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) {
+   |                --  -- lifetime `'b` defined here
+   |                |
+   |                lifetime `'a` defined here
+LL |     x == y;
+   |     ^ requires that `'a` must outlive `'b`
+
+error: lifetime may not live long enough
+  --> $DIR/type-check-pointer-comparisons.rs:12:10
+   |
+LL | fn compare_mut<'a, 'b>(x: *mut &'a i32, y: *mut &'b i32) {
+   |                --  -- lifetime `'b` defined here
+   |                |
+   |                lifetime `'a` defined here
+LL |     x == y;
+   |          ^ requires that `'b` must outlive `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/type-check-pointer-comparisons.rs:18:5
+   |
+LL | fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32)) {
+   |                   --  -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+LL |     f == g;
+   |     ^ requires that `'a` must outlive `'b`
+
+error: lifetime may not live long enough
+  --> $DIR/type-check-pointer-comparisons.rs:18:10
+   |
+LL | fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32)) {
+   |                   --  -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+LL |     f == g;
+   |          ^ requires that `'b` must outlive `'a`
+
+error: aborting due to 6 previous errors
+