about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-04-15 09:14:43 +0000
committerbors <bors@rust-lang.org>2018-04-15 09:14:43 +0000
commit602b3957f152a486e57f7fbaa15265d8a81017bc (patch)
tree031ef25c436812794776c1a37ddf84f0c62a298a
parent56109dbf709c2e4f6ca27d79feba2155b7f66e03 (diff)
parent55fb12c274898b56d05e4ee8c97d4417e38e8ecc (diff)
downloadrust-602b3957f152a486e57f7fbaa15265d8a81017bc.tar.gz
rust-602b3957f152a486e57f7fbaa15265d8a81017bc.zip
Auto merge of #49885 - spastorino:fn_ref_unsound, r=nikomatsakis
Fix unsoundness bug in functions input references

Fixes #48803

r? @nikomatsakis
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs55
-rw-r--r--src/test/ui/issue-48803.rs25
-rw-r--r--src/test/ui/issue-48803.stderr15
3 files changed, 75 insertions, 20 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 544cb5eefc8..faa382738b0 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -14,20 +14,20 @@
 use borrow_check::nll::region_infer::Cause;
 use borrow_check::nll::region_infer::ClosureRegionRequirementsExt;
 use borrow_check::nll::universal_regions::UniversalRegions;
+use dataflow::move_paths::MoveData;
 use dataflow::FlowAtLocation;
 use dataflow::MaybeInitializedPlaces;
-use dataflow::move_paths::MoveData;
 use rustc::hir::def_id::DefId;
-use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
 use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
-use rustc::traits::{self, Normalized, TraitEngine};
+use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
+use rustc::mir::tcx::PlaceTy;
+use rustc::mir::visit::{PlaceContext, Visitor};
+use rustc::mir::*;
 use rustc::traits::query::NoSolution;
+use rustc::traits::{self, Normalized, TraitEngine};
 use rustc::ty::error::TypeError;
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
-use rustc::mir::*;
-use rustc::mir::tcx::PlaceTy;
-use rustc::mir::visit::{PlaceContext, Visitor};
 use std::fmt;
 use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
@@ -61,8 +61,8 @@ macro_rules! span_mirbug_and_err {
     })
 }
 
-mod liveness;
 mod input_output;
+mod liveness;
 
 /// Type checks the given `mir` in the context of the inference
 /// context `infcx`. Returns any region constraints that have yet to
@@ -275,7 +275,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                         tcx.predicates_of(def_id).instantiate(tcx, substs);
                     let predicates =
                         type_checker.normalize(&instantiated_predicates.predicates, location);
-                    type_checker.prove_predicates(&predicates, location);
+                    type_checker.prove_predicates(predicates.iter().cloned(), location);
                 }
 
                 value.ty
@@ -763,9 +763,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             }
             StatementKind::UserAssertTy(ref c_ty, ref local) => {
                 let local_ty = mir.local_decls()[*local].ty;
-                let (ty, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
-                    stmt.source_info.span, c_ty);
-                debug!("check_stmt: user_assert_ty ty={:?} local_ty={:?}", ty, local_ty);
+                let (ty, _) = self.infcx
+                    .instantiate_canonical_with_fresh_inference_vars(stmt.source_info.span, c_ty);
+                debug!(
+                    "check_stmt: user_assert_ty ty={:?} local_ty={:?}",
+                    ty, local_ty
+                );
                 if let Err(terr) = self.eq_types(ty, local_ty, location.at_self()) {
                     span_mirbug!(
                         self,
@@ -895,6 +898,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 let sig = self.normalize(&sig, term_location);
                 self.check_call_dest(mir, term, &sig, destination, term_location);
 
+                self.prove_predicates(
+                    sig.inputs().iter().map(|ty| ty::Predicate::WellFormed(ty)),
+                    term_location,
+                );
+
                 // The ordinary liveness rules will ensure that all
                 // regions in the type of the callee are live here. We
                 // then further constrain the late-bound regions that
@@ -1508,28 +1516,35 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
         let predicates = self.normalize(&instantiated_predicates.predicates, location);
         debug!("prove_aggregate_predicates: predicates={:?}", predicates);
-        self.prove_predicates(&predicates, location);
+        self.prove_predicates(predicates.iter().cloned(), location);
     }
 
     fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, location: Location) {
         self.prove_predicates(
-            &[
-                ty::Predicate::Trait(trait_ref.to_poly_trait_ref().to_poly_trait_predicate()),
-            ],
+            [ty::Predicate::Trait(
+                trait_ref.to_poly_trait_ref().to_poly_trait_predicate(),
+            )].iter()
+                .cloned(),
             location,
         );
     }
 
-    fn prove_predicates(&mut self, predicates: &[ty::Predicate<'tcx>], location: Location) {
+    fn prove_predicates(
+        &mut self,
+        predicates: impl IntoIterator<Item = ty::Predicate<'tcx>>,
+        location: Location,
+    ) {
+        let mut predicates_iter = predicates.into_iter();
+
         debug!(
             "prove_predicates(predicates={:?}, location={:?})",
-            predicates, location
+            predicates_iter.by_ref().collect::<Vec<_>>(),
+            location
         );
         self.fully_perform_op(location.at_self(), |this| {
             let cause = this.misc(this.last_span);
-            let obligations = predicates
-                .iter()
-                .map(|&p| traits::Obligation::new(cause.clone(), this.param_env, p))
+            let obligations = predicates_iter
+                .map(|p| traits::Obligation::new(cause.clone(), this.param_env, p))
                 .collect();
             Ok(InferOk {
                 value: (),
diff --git a/src/test/ui/issue-48803.rs b/src/test/ui/issue-48803.rs
new file mode 100644
index 00000000000..c6d14ace8b3
--- /dev/null
+++ b/src/test/ui/issue-48803.rs
@@ -0,0 +1,25 @@
+// Copyright 2018 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(nll)]
+
+fn flatten<'a, 'b, T>(x: &'a &'b T) -> &'a T {
+    x
+}
+
+fn main() {
+    let mut x = "original";
+    let y = &x;
+    let z = &y;
+    let w = flatten(z);
+    x = "modified";
+    //~^ ERROR cannot assign to `x` because it is borrowed [E0506]
+    println!("{}", w); // prints "modified"
+}
diff --git a/src/test/ui/issue-48803.stderr b/src/test/ui/issue-48803.stderr
new file mode 100644
index 00000000000..b37e2c07d23
--- /dev/null
+++ b/src/test/ui/issue-48803.stderr
@@ -0,0 +1,15 @@
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/issue-48803.rs:22:5
+   |
+LL |     let y = &x;
+   |             -- borrow of `x` occurs here
+...
+LL |     x = "modified";
+   |     ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here
+LL |     //~^ ERROR cannot assign to `x` because it is borrowed [E0506]
+LL |     println!("{}", w); // prints "modified"
+   |                    - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.