about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarvin Löbel <loebel.marvin@gmail.com>2014-05-04 10:39:11 +0200
committerAlex Crichton <alex@alexcrichton.com>2014-05-13 17:24:07 -0700
commit24ece07cecf3df59ce7b9ed3b317e3ffd718f756 (patch)
treefb613b5174d8991cfb3a74b8d46bb76029f9d943
parentcbc31df4fc084b47a5c6456df2efb6e28b82a7da (diff)
downloadrust-24ece07cecf3df59ce7b9ed3b317e3ffd718f756.tar.gz
rust-24ece07cecf3df59ce7b9ed3b317e3ffd718f756.zip
Allow blocks in const expressions
Only blocks with tail expressions that are const expressions
and items are allowed.
-rw-r--r--src/librustc/middle/check_const.rs27
-rw-r--r--src/librustc/middle/const_eval.rs14
-rw-r--r--src/librustc/middle/trans/base.rs3
-rw-r--r--src/librustc/middle/trans/consts.rs6
-rw-r--r--src/librustc/middle/typeck/check/mod.rs6
-rw-r--r--src/test/auxiliary/cci_const_block.rs16
-rw-r--r--src/test/compile-fail/const-block-non-item-statement.rs28
-rw-r--r--src/test/run-pass/const-block-cross-crate-fn.rs17
-rw-r--r--src/test/run-pass/const-block-item-macro-codegen.rs49
-rw-r--r--src/test/run-pass/const-block-item.rs56
-rw-r--r--src/test/run-pass/const-block.rs69
11 files changed, 290 insertions, 1 deletions
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index f5f551e36f7..7da56655378 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -148,6 +148,33 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
                 }
             }
           }
+          ExprBlock(ref block) => {
+            // Check all statements in the block
+            for stmt in block.stmts.iter() {
+                let block_span_err = |span|
+                    v.tcx.sess.span_err(span,
+                        "blocks in constants are limited to \
+                        items and tail expressions");
+                match stmt.node {
+                    StmtDecl(ref span, _) => {
+                        match span.node {
+                            DeclLocal(_) => block_span_err(span.span),
+
+                            // Item statements are allowed
+                            DeclItem(_) => {}
+                        }
+                    }
+                    StmtExpr(ref expr, _) => block_span_err(expr.span),
+                    StmtSemi(ref semi, _) => block_span_err(semi.span),
+                    StmtMac(..) => v.tcx.sess.span_bug(e.span,
+                        "unexpanded statement macro in const?!")
+                }
+            }
+            match block.expr {
+                Some(ref expr) => check_expr(v, &**expr, true),
+                None => {}
+            }
+          }
           ExprVstore(_, ExprVstoreMutSlice) |
           ExprVstore(_, ExprVstoreSlice) |
           ExprVec(_) |
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 34f36363b92..aa0b573eba8 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -47,7 +47,6 @@ use std::rc::Rc;
 //        fixed-size vectors and strings: [] and ""/_
 //        vector and string slices: &[] and &""
 //        tuples: (,)
-//        records: {...}
 //        enums: foo(...)
 //        floating point literals and operators
 //        & and * pointers
@@ -241,6 +240,13 @@ impl<'a> ConstEvalVisitor<'a> {
 
             ast::ExprRepeat(..) => general_const,
 
+            ast::ExprBlock(ref block) => {
+                match block.expr {
+                    Some(ref e) => self.classify(&**e),
+                    None => integral_const
+                }
+            }
+
             _ => non_const
         };
         self.ccache.insert(did, cn);
@@ -479,6 +485,12 @@ pub fn eval_const_expr_partial<T: ty::ExprTyProvider>(tcx: &T, e: &Expr)
       // If we have a vstore, just keep going; it has to be a string
       ExprVstore(e, _) => eval_const_expr_partial(tcx, e),
       ExprParen(e)     => eval_const_expr_partial(tcx, e),
+      ExprBlock(ref block) => {
+        match block.expr {
+            Some(ref expr) => eval_const_expr_partial(tcx, &**expr),
+            None => Ok(const_int(0i64))
+        }
+      }
       _ => Err("unsupported constant expr".to_strbuf())
     }
 }
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 10f35255abb..3cfabf7f96b 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -1611,6 +1611,9 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
         }
       }
       ast::ItemStatic(_, m, expr) => {
+          // Recurse on the expression to catch items in blocks
+          let mut v = TransItemVisitor{ ccx: ccx };
+          v.visit_expr(expr, ());
           consts::trans_const(ccx, m, item.id);
           // Do static_assert checking. It can't really be done much earlier
           // because we need to get the value of the bool out of LLVM
diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs
index 548746362cf..b5ab0a391f3 100644
--- a/src/librustc/middle/trans/consts.rs
+++ b/src/librustc/middle/trans/consts.rs
@@ -672,6 +672,12 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
               }
           }
           ast::ExprParen(e) => { const_expr(cx, e, is_local) }
+          ast::ExprBlock(ref block) => {
+            match block.expr {
+                Some(ref expr) => const_expr(cx, &**expr, is_local),
+                None => (C_nil(cx), true)
+            }
+          }
           _ => cx.sess().span_bug(e.span,
                   "bad constant expression type in consts::const_expr")
         };
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 6be96a408b8..68f4fd95626 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -3554,6 +3554,12 @@ pub fn check_const_with_ty(fcx: &FnCtxt,
                            _: Span,
                            e: &ast::Expr,
                            declty: ty::t) {
+    // Gather locals in statics (because of block expressions).
+    // This is technically uneccessary because locals in static items are forbidden,
+    // but prevents type checking from blowing up before const checking can properly
+    // emit a error.
+    GatherLocalsVisitor { fcx: fcx }.visit_expr(e, ());
+
     check_expr(fcx, e);
     let cty = fcx.expr_ty(e);
     demand::suptype(fcx, e.span, declty, cty);
diff --git a/src/test/auxiliary/cci_const_block.rs b/src/test/auxiliary/cci_const_block.rs
new file mode 100644
index 00000000000..a3bcbd201e1
--- /dev/null
+++ b/src/test/auxiliary/cci_const_block.rs
@@ -0,0 +1,16 @@
+// 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.
+
+pub static BLOCK_FN_DEF: fn(uint) -> uint = {
+    fn foo(a: uint) -> uint {
+        a + 10
+    }
+    foo
+};
diff --git a/src/test/compile-fail/const-block-non-item-statement.rs b/src/test/compile-fail/const-block-non-item-statement.rs
new file mode 100644
index 00000000000..ace917c704a
--- /dev/null
+++ b/src/test/compile-fail/const-block-non-item-statement.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.
+
+#![feature(macro_rules)]
+
+static A: uint = { 1; 2 };
+//~^ ERROR: blocks in constants are limited to items and tail expressions
+
+static B: uint = { { } 2 };
+//~^ ERROR: blocks in constants are limited to items and tail expressions
+
+macro_rules! foo {
+    () => (()) //~ ERROR: blocks in constants are limited to items and tail expressions
+}
+static C: uint = { foo!() 2 };
+
+static D: uint = { let x = 4; 2 };
+//~^ ERROR: blocks in constants are limited to items and tail expressions
+
+pub fn main() {
+}
diff --git a/src/test/run-pass/const-block-cross-crate-fn.rs b/src/test/run-pass/const-block-cross-crate-fn.rs
new file mode 100644
index 00000000000..16360ff08d0
--- /dev/null
+++ b/src/test/run-pass/const-block-cross-crate-fn.rs
@@ -0,0 +1,17 @@
+// 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.
+
+// aux-build:cci_const_block.rs
+
+extern crate cci_const_block;
+
+pub fn main() {
+    assert_eq!(cci_const_block::BLOCK_FN_DEF(390), 400);
+}
diff --git a/src/test/run-pass/const-block-item-macro-codegen.rs b/src/test/run-pass/const-block-item-macro-codegen.rs
new file mode 100644
index 00000000000..09f26b15734
--- /dev/null
+++ b/src/test/run-pass/const-block-item-macro-codegen.rs
@@ -0,0 +1,49 @@
+// 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.
+
+// General test that function items in static blocks
+// can be generated with a macro.
+
+#![feature(macro_rules)]
+
+struct MyType {
+    desc: &'static str,
+    data: uint,
+    code: fn(uint, uint) -> uint
+}
+
+impl MyType {
+    fn eval(&self, a: uint) -> uint {
+        (self.code)(self.data, a)
+    }
+}
+
+macro_rules! codegen {
+    ($e:expr, $v:expr) => {
+        {
+            fn generated(a: uint, b: uint) -> uint {
+                a - ($e * b)
+            }
+            MyType {
+                desc: "test",
+                data: $v,
+                code: generated
+            }
+        }
+    }
+}
+
+static GENERATED_CODE_1: MyType = codegen!(2, 100);
+static GENERATED_CODE_2: MyType = codegen!(5, 1000);
+
+pub fn main() {
+    assert_eq!(GENERATED_CODE_1.eval(10), 80);
+    assert_eq!(GENERATED_CODE_2.eval(100), 500);
+}
diff --git a/src/test/run-pass/const-block-item.rs b/src/test/run-pass/const-block-item.rs
new file mode 100644
index 00000000000..3365f09cd80
--- /dev/null
+++ b/src/test/run-pass/const-block-item.rs
@@ -0,0 +1,56 @@
+// 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.
+
+#![feature(macro_rules)]
+
+mod foo {
+    pub trait Value {
+        fn value(&self) -> uint;
+    }
+}
+
+static BLOCK_USE: uint = {
+    use foo::Value;
+    100
+};
+
+static BLOCK_PUB_USE: uint = {
+    pub use foo::Value;
+    200
+};
+
+static BLOCK_STRUCT_DEF: uint = {
+    struct Foo {
+        a: uint
+    }
+    Foo{ a: 300 }.a
+};
+
+static BLOCK_FN_DEF: fn(uint) -> uint = {
+    fn foo(a: uint) -> uint {
+        a + 10
+    }
+    foo
+};
+
+static BLOCK_MACRO_RULES: uint = {
+    macro_rules! baz {
+        () => (412)
+    }
+    baz!()
+};
+
+pub fn main() {
+    assert_eq!(BLOCK_USE, 100);
+    assert_eq!(BLOCK_PUB_USE, 200);
+    assert_eq!(BLOCK_STRUCT_DEF, 300);
+    assert_eq!(BLOCK_FN_DEF(390), 400);
+    assert_eq!(BLOCK_MACRO_RULES, 412);
+}
diff --git a/src/test/run-pass/const-block.rs b/src/test/run-pass/const-block.rs
new file mode 100644
index 00000000000..feac6e68e48
--- /dev/null
+++ b/src/test/run-pass/const-block.rs
@@ -0,0 +1,69 @@
+// 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.
+
+#![allow(dead_code)]
+#![allow(unused_unsafe)]
+
+struct Foo {
+    a: uint,
+    b: *()
+}
+
+fn foo<T>(a: T) -> T {
+    a
+}
+
+static BLOCK_INTEGRAL: uint = { 1 };
+static BLOCK_EXPLICIT_UNIT: () = { () };
+static BLOCK_IMPLICIT_UNIT: () = { };
+static BLOCK_FLOAT: f64 = { 1.0 };
+static BLOCK_ENUM: Option<uint> = { Some(100) };
+static BLOCK_STRUCT: Foo = { Foo { a: 12, b: 0 as *() } };
+static BLOCK_UNSAFE: uint = unsafe { 1000 };
+
+// FIXME: #13970
+// static BLOCK_FN_INFERRED: fn(uint) -> uint = { foo };
+
+// FIXME: #13971
+// static BLOCK_FN: fn(uint) -> uint = { foo::<uint> };
+
+// FIXME: #13972
+// static BLOCK_ENUM_CONSTRUCTOR: fn(uint) -> Option<uint> = { Some };
+
+// FIXME: #13973
+// static BLOCK_UNSAFE_SAFE_PTR: &'static int = unsafe { &*(0xdeadbeef as *int) };
+// static BLOCK_UNSAFE_SAFE_PTR_2: &'static int = unsafe {
+//     static X: *int = 0xdeadbeef as *int;
+//     &*X
+// };
+
+pub fn main() {
+    assert_eq!(BLOCK_INTEGRAL, 1);
+    assert_eq!(BLOCK_EXPLICIT_UNIT, ());
+    assert_eq!(BLOCK_IMPLICIT_UNIT, ());
+    assert_eq!(BLOCK_FLOAT, 1.0_f64);
+    assert_eq!(BLOCK_STRUCT.a, 12);
+    assert_eq!(BLOCK_STRUCT.b, 0 as *());
+    assert_eq!(BLOCK_ENUM, Some(100));
+    assert_eq!(BLOCK_UNSAFE, 1000);
+
+    // FIXME: #13970
+    // assert_eq!(BLOCK_FN_INFERRED(300), 300);
+
+    // FIXME: #13971
+    // assert_eq!(BLOCK_FN(300), 300);
+
+    // FIXME: #13972
+    // assert_eq!(BLOCK_ENUM_CONSTRUCTOR(200), Some(200));
+
+    // FIXME: #13973
+    // assert_eq!(BLOCK_UNSAFE_SAFE_PTR as *int as uint, 0xdeadbeef_u);
+    // assert_eq!(BLOCK_UNSAFE_SAFE_PTR_2 as *int as uint, 0xdeadbeef_u);
+}