about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrandon Sanderson <singingboyo@gmail.com>2014-11-05 15:05:01 -0800
committerBrandon Sanderson <singingboyo@gmail.com>2014-11-06 10:42:40 -0800
commitd80a62d84bc9fbc9ae7c8bd300bf5416249b51f7 (patch)
treeaa89a6df3261fd315f2667f4dc794f38bbbccfd7
parent60a669a1743b845dfa349684ef057bc98ec6d840 (diff)
downloadrust-d80a62d84bc9fbc9ae7c8bd300bf5416249b51f7.tar.gz
rust-d80a62d84bc9fbc9ae7c8bd300bf5416249b51f7.zip
Fix soundness hole in struct with expressions.
Fixes #18567. Struct{x:foo, .. with_expr} did not walk with_expr, which allowed
using moved variables in some cases.  The CFG for structs also built up with
with_expr happening before the fields, which is now reversed. (Fields are now
before the with_expr in the CFG)
-rw-r--r--src/librustc/middle/cfg/construct.rs4
-rw-r--r--src/librustc/middle/expr_use_visitor.rs4
-rw-r--r--src/test/compile-fail/walk-struct-literal-with.rs28
3 files changed, 34 insertions, 2 deletions
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index 146891825d6..1419c48609b 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -448,8 +448,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             }
 
             ast::ExprStruct(_, ref fields, ref base) => {
-                let base_exit = self.opt_expr(base, pred);
-                self.straightline(expr, base_exit, fields.iter().map(|f| &*f.expr))
+                let field_cfg = self.straightline(expr, pred, fields.iter().map(|f| &*f.expr));
+                self.opt_expr(base, field_cfg)
             }
 
             ast::ExprRepeat(ref elem, ref count) => {
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index e8a85b89b58..33a8cf43e72 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -672,6 +672,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> {
             }
         }
 
+        // walk the with expression so that complex expressions
+        // are properly handled.
+        self.walk_expr(with_expr);
+
         fn contains_field_named(field: &ty::field,
                                 fields: &Vec<ast::Field>)
                                 -> bool
diff --git a/src/test/compile-fail/walk-struct-literal-with.rs b/src/test/compile-fail/walk-struct-literal-with.rs
new file mode 100644
index 00000000000..bb3b310a68f
--- /dev/null
+++ b/src/test/compile-fail/walk-struct-literal-with.rs
@@ -0,0 +1,28 @@
+// Copyright 2014 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 Mine{
+    test: String,
+    other_val: int
+}
+
+impl Mine{
+    fn make_string_bar(mut self) -> Mine{
+        self.test = "Bar".to_string();
+        self
+    }
+}
+
+fn main(){
+    let start = Mine{test:"Foo".to_string(), other_val:0};
+    let end = Mine{other_val:1, ..start.make_string_bar()};
+    println!("{}", start.test); //~ ERROR use of moved value: `start.test`
+}
+