Permalink
Browse files

Allow blocks in const expressions

Only blocks with tail expressions that are const expressions
and items are allowed.
  • Loading branch information...
1 parent cbc31df commit 24ece07cecf3df59ce7b9ed3b317e3ffd718f756 @Kimundi Kimundi committed with alexcrichton May 4, 2014
@@ -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(_) |
@@ -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())
}
}
@@ -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
@@ -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")
};
@@ -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);
@@ -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
+};
@@ -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() {
+}
@@ -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);
+}
@@ -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);
+}
@@ -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);
+}
@@ -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);
+}

0 comments on commit 24ece07

Please sign in to comment.