From 742f49c961426be422c479c7e47957c45e560ba6 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 2 Sep 2014 15:55:07 +1200 Subject: [PATCH] Forbid unsized rvalues Closes #16813 --- src/librustc/diagnostics.rs | 3 +- src/librustc/driver/driver.rs | 3 + src/librustc/lib.rs | 1 + src/librustc/middle/check_rvalues.rs | 86 +++++++++++++++++++++++ src/librustc/middle/mem_categorization.rs | 2 +- src/test/compile-fail/dst-bad-assign-2.rs | 1 + src/test/compile-fail/dst-bad-deep.rs | 1 + src/test/compile-fail/dst-rvalue.rs | 20 ++++++ src/test/compile-fail/issue-5883.rs | 2 + src/test/compile-fail/unsized3.rs | 6 +- src/test/compile-fail/unsized6.rs | 2 + 11 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 src/librustc/middle/check_rvalues.rs create mode 100644 src/test/compile-fail/dst-rvalue.rs diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index fdc0779b2bc..079e01c6ed6 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -169,5 +169,6 @@ register_diagnostics!( E0157, E0158, E0159, - E0160 + E0160, + E0161 ) diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 09bf69bff4c..d46eecc1d63 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -404,6 +404,9 @@ pub fn phase_3_run_analysis_passes(sess: Session, time(time_passes, "borrow checking", (), |_| middle::borrowck::check_crate(&ty_cx, krate)); + time(time_passes, "rvalue checking", (), |_| + middle::check_rvalues::check_crate(&ty_cx, krate)); + time(time_passes, "kind checking", (), |_| kind::check_crate(&ty_cx, krate)); diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index e4eac80c4af..75a48fdd596 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -80,6 +80,7 @@ pub mod middle { pub mod check_const; pub mod check_loop; pub mod check_match; + pub mod check_rvalues; pub mod check_static; pub mod const_eval; pub mod dataflow; diff --git a/src/librustc/middle/check_rvalues.rs b/src/librustc/middle/check_rvalues.rs new file mode 100644 index 00000000000..0ac6f21dc1f --- /dev/null +++ b/src/librustc/middle/check_rvalues.rs @@ -0,0 +1,86 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks that all rvalues in a crate have statically known size. check_crate +// is the public starting point. + +use middle::expr_use_visitor as euv; +use middle::mem_categorization as mc; +use middle::ty; +use util::ppaux::ty_to_string; + +use syntax::ast; +use syntax::codemap::Span; +use syntax::visit; + +pub fn check_crate(tcx: &ty::ctxt, + krate: &ast::Crate) { + let mut rvcx = RvalueContext { tcx: tcx }; + visit::walk_crate(&mut rvcx, krate, ()); +} + +struct RvalueContext<'a> { + tcx: &'a ty::ctxt +} + +impl<'a> visit::Visitor<()> for RvalueContext<'a> { + fn visit_fn(&mut self, + _: &visit::FnKind, + fd: &ast::FnDecl, + b: &ast::Block, + _: Span, + _: ast::NodeId, + _: ()) { + let mut euv = euv::ExprUseVisitor::new(self, self.tcx); + euv.walk_fn(fd, b); + } +} + +impl<'a> euv::Delegate for RvalueContext<'a> { + fn consume(&mut self, + _: ast::NodeId, + span: Span, + cmt: mc::cmt, + _: euv::ConsumeMode) { + debug!("consume; cmt: {:?}; type: {}", *cmt, ty_to_string(self.tcx, cmt.ty)); + if !ty::type_is_sized(self.tcx, cmt.ty) { + span_err!(self.tcx.sess, span, E0161, + "cannot move a value of type {0}: the size of {0} cannot be statically determined", + ty_to_string(self.tcx, cmt.ty)); + } + } + + fn consume_pat(&mut self, + _consume_pat: &ast::Pat, + _cmt: mc::cmt, + _mode: euv::ConsumeMode) { + } + + fn borrow(&mut self, + _borrow_id: ast::NodeId, + _borrow_span: Span, + _cmt: mc::cmt, + _loan_region: ty::Region, + _bk: ty::BorrowKind, + _loan_cause: euv::LoanCause) { + } + + fn decl_without_init(&mut self, + _id: ast::NodeId, + _span: Span) { + } + + fn mutate(&mut self, + _assignment_id: ast::NodeId, + _assignment_span: Span, + _assignee_cmt: mc::cmt, + _mode: euv::MutateMode) { + } +} diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 23cab419aa2..56e501388f1 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -150,7 +150,7 @@ pub enum MutabilityCategory { // like `*x`, the type of this deref node is the deref'd type (`T`), // but in a pattern like `@x`, the `@x` pattern is again a // dereference, but its type is the type *before* the dereference -// (`@T`). So use `cmt.type` to find the type of the value in a consistent +// (`@T`). So use `cmt.ty` to find the type of the value in a consistent // fashion. For more details, see the method `cat_pattern` #[deriving(Clone, PartialEq)] pub struct cmt_ { diff --git a/src/test/compile-fail/dst-bad-assign-2.rs b/src/test/compile-fail/dst-bad-assign-2.rs index 08e51038104..76becdc855d 100644 --- a/src/test/compile-fail/dst-bad-assign-2.rs +++ b/src/test/compile-fail/dst-bad-assign-2.rs @@ -43,4 +43,5 @@ pub fn main() { let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; let z: Box = box Bar1 {f: 36}; f5.ptr = *z; //~ ERROR dynamically sized type on lhs of assignment + //~^ ERROR E0161 } diff --git a/src/test/compile-fail/dst-bad-deep.rs b/src/test/compile-fail/dst-bad-deep.rs index cf526392283..e2e387e1a48 100644 --- a/src/test/compile-fail/dst-bad-deep.rs +++ b/src/test/compile-fail/dst-bad-deep.rs @@ -22,4 +22,5 @@ pub fn main() { let g: &Fat<[int]> = &f; let h: &Fat> = &Fat { ptr: *g }; //~^ ERROR trying to initialise a dynamically sized struct + //~^^ ERROR E0161 } diff --git a/src/test/compile-fail/dst-rvalue.rs b/src/test/compile-fail/dst-rvalue.rs new file mode 100644 index 00000000000..52b7ea9efa5 --- /dev/null +++ b/src/test/compile-fail/dst-rvalue.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that dynamically sized rvalues are forbidden + +pub fn main() { + let _x: Box = box *"hello world"; + //~^ ERROR E0161 + + let array: &[int] = &[1, 2, 3]; + let _x: Box<[int]> = box *array; + //~^ ERROR E0161 +} diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index f3bbb8051b7..7ea282c599f 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -17,6 +17,8 @@ struct Struct { fn new_struct(r: A+'static) -> Struct { //~^ ERROR variable `r` has dynamically sized type Struct { r: r } //~ ERROR trying to initialise a dynamically sized struct + //~^ ERROR E0161 + //~^^ ERROR E0161 } trait Curve {} diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs index 50e109b9934..cf42e79b394 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -51,8 +51,10 @@ fn f8(x1: &S, x2: &S) { // Test some tuples. fn f9(x1: Box>, x2: Box>) { - f5(&(*x1, 34i)); //~ERROR instantiating a type parameter with an incompatible type `(S,int)`, - f5(&(32i, *x2)); //~ERROR instantiating a type parameter with an incompatible type `(int,E)`, + f5(&(*x1, 34i)); //~ERROR E0161 + //~^ ERROR instantiating a type parameter with an incompatible type + f5(&(32i, *x2)); //~ERROR E0161 + //~^ ERROR instantiating a type parameter with an incompatible type } // I would like these to fail eventually. diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index def1146526b..6618cce0214 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -30,11 +30,13 @@ fn f3(x1: Box, x2: Box, x3: Box) { let y: X = *x1; //~ERROR variable `y` has dynamically sized type `X` let y = *x2; //~ERROR variable `y` has dynamically sized type `X` let (y, z) = (*x3, 4i); //~ERROR variable `y` has dynamically sized type `X` + //~^ ERROR E0161 } fn f4(x1: Box, x2: Box, x3: Box) { let y: X = *x1; //~ERROR variable `y` has dynamically sized type `X` let y = *x2; //~ERROR variable `y` has dynamically sized type `X` let (y, z) = (*x3, 4i); //~ERROR variable `y` has dynamically sized type `X` + //~^ ERROR E0161 } fn g1(x: X) {} //~ERROR variable `x` has dynamically sized type `X`