about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-03-05 03:12:43 -0800
committerbors <bors@rust-lang.org>2013-03-05 03:12:43 -0800
commit65986ba0c0b20803dd02a5b0b71e269cbeb8336d (patch)
tree1fd4c8804e44088151d647ee5e2ad12dd1002a87
parenteddefbc893f16ddec44dbb6b5be6adf7d84c2b53 (diff)
parenteb1c632201a9b9f03abfef816fb9625d3f014600 (diff)
downloadrust-65986ba0c0b20803dd02a5b0b71e269cbeb8336d.tar.gz
rust-65986ba0c0b20803dd02a5b0b71e269cbeb8336d.zip
auto merge of #5215 : jld/rust/fn-const-env, r=graydon
Fixes #5210; unblocks #5183.
-rw-r--r--src/librustc/middle/trans/consts.rs38
-rw-r--r--src/test/run-pass/const-vec-of-fns.rs27
2 files changed, 60 insertions, 5 deletions
diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs
index 36cda3dfbe9..e61afbdce25 100644
--- a/src/librustc/middle/trans/consts.rs
+++ b/src/librustc/middle/trans/consts.rs
@@ -20,6 +20,7 @@ use middle::trans::expr;
 use middle::trans::machine;
 use middle::trans::type_of;
 use middle::ty;
+use util::ppaux::{expr_repr, ty_to_str};
 
 use core::libc::c_uint;
 use syntax::{ast, ast_util, codemap, ast_map};
@@ -150,6 +151,24 @@ pub fn get_const_val(cx: @CrateContext, def_id: ast::def_id) -> ValueRef {
 }
 
 pub fn const_expr(cx: @CrateContext, e: @ast::expr) -> ValueRef {
+    let ety = ty::expr_ty_adjusted(cx.tcx, e);
+    let llty = type_of::sizing_type_of(cx, ety);
+    let llconst = const_expr_unchecked(cx, e);
+    let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
+    let tsize = machine::llsize_of_alloc(cx, llty);
+    if csize != tsize {
+        unsafe {
+            llvm::LLVMDumpValue(llconst);
+            llvm::LLVMDumpValue(C_null(llty));
+        }
+        cx.sess.bug(fmt!("const %s of type %s has size %u instead of %u",
+                         expr_repr(cx.tcx, e), ty_to_str(cx.tcx, ety),
+                         csize, tsize));
+    }
+    llconst
+}
+
+fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef {
     unsafe {
         let _icx = cx.insn_ctxt("const_expr");
         return match /*bad*/copy e.node {
@@ -394,13 +413,22 @@ pub fn const_expr(cx: @CrateContext, e: @ast::expr) -> ValueRef {
           ast::expr_path(pth) => {
             assert pth.types.len() == 0;
             match cx.tcx.def_map.find(&e.id) {
-                Some(ast::def_fn(def_id, purity)) => {
+                Some(ast::def_fn(def_id, _purity)) => {
                     assert ast_util::is_local(def_id);
                     let f = base::get_item_val(cx, def_id.node);
-                    match purity {
-                      ast::extern_fn =>
-                        llvm::LLVMConstPointerCast(f, T_ptr(T_i8())),
-                      _ => C_struct(~[f, C_null(T_opaque_box_ptr(cx))])
+                    let ety = ty::expr_ty_adjusted(cx.tcx, e);
+                    match ty::get(ety).sty {
+                        ty::ty_bare_fn(*) | ty::ty_ptr(*) => {
+                            llvm::LLVMConstPointerCast(f, T_ptr(T_i8()))
+                        }
+                        ty::ty_closure(*) => {
+                            C_struct(~[f, C_null(T_opaque_box_ptr(cx))])
+                        }
+                        _ => {
+                            cx.sess.span_bug(e.span, fmt!(
+                                "unexpected const fn type: %s",
+                                ty_to_str(cx.tcx, ety)))
+                        }
                     }
                 }
                 Some(ast::def_const(def_id)) => {
diff --git a/src/test/run-pass/const-vec-of-fns.rs b/src/test/run-pass/const-vec-of-fns.rs
new file mode 100644
index 00000000000..bf7472aeb36
--- /dev/null
+++ b/src/test/run-pass/const-vec-of-fns.rs
@@ -0,0 +1,27 @@
+// Copyright 2013 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.
+
+/*!
+ * Try to double-check that const fns have the right size (with or
+ * without dummy env ptr, as appropriate) by iterating a size-2 array.
+ * If the const size differs from the runtime size, the second element
+ * should be read as a null or otherwise wrong pointer and crash.
+ */
+
+fn f() { }
+const bare_fns: &[extern fn()] = &[f, f];
+// NOTE Why does this not type without the struct?
+struct S(&fn());
+const closures: &[S] = &[S(f), S(f)];
+
+pub fn main() {
+    for bare_fns.each |&bare_fn| { bare_fn() }
+    for closures.each |&closure| { (*closure)() }
+}