Skip to content

Commit 65986ba

Browse files
committed
auto merge of #5215 : jld/rust/fn-const-env, r=graydon
Fixes #5210; unblocks #5183.
2 parents eddefbc + eb1c632 commit 65986ba

File tree

2 files changed

+60
-5
lines changed

2 files changed

+60
-5
lines changed

src/librustc/middle/trans/consts.rs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use middle::trans::expr;
2020
use middle::trans::machine;
2121
use middle::trans::type_of;
2222
use middle::ty;
23+
use util::ppaux::{expr_repr, ty_to_str};
2324

2425
use core::libc::c_uint;
2526
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 {
150151
}
151152

152153
pub fn const_expr(cx: @CrateContext, e: @ast::expr) -> ValueRef {
154+
let ety = ty::expr_ty_adjusted(cx.tcx, e);
155+
let llty = type_of::sizing_type_of(cx, ety);
156+
let llconst = const_expr_unchecked(cx, e);
157+
let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
158+
let tsize = machine::llsize_of_alloc(cx, llty);
159+
if csize != tsize {
160+
unsafe {
161+
llvm::LLVMDumpValue(llconst);
162+
llvm::LLVMDumpValue(C_null(llty));
163+
}
164+
cx.sess.bug(fmt!("const %s of type %s has size %u instead of %u",
165+
expr_repr(cx.tcx, e), ty_to_str(cx.tcx, ety),
166+
csize, tsize));
167+
}
168+
llconst
169+
}
170+
171+
fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef {
153172
unsafe {
154173
let _icx = cx.insn_ctxt("const_expr");
155174
return match /*bad*/copy e.node {
@@ -394,13 +413,22 @@ pub fn const_expr(cx: @CrateContext, e: @ast::expr) -> ValueRef {
394413
ast::expr_path(pth) => {
395414
assert pth.types.len() == 0;
396415
match cx.tcx.def_map.find(&e.id) {
397-
Some(ast::def_fn(def_id, purity)) => {
416+
Some(ast::def_fn(def_id, _purity)) => {
398417
assert ast_util::is_local(def_id);
399418
let f = base::get_item_val(cx, def_id.node);
400-
match purity {
401-
ast::extern_fn =>
402-
llvm::LLVMConstPointerCast(f, T_ptr(T_i8())),
403-
_ => C_struct(~[f, C_null(T_opaque_box_ptr(cx))])
419+
let ety = ty::expr_ty_adjusted(cx.tcx, e);
420+
match ty::get(ety).sty {
421+
ty::ty_bare_fn(*) | ty::ty_ptr(*) => {
422+
llvm::LLVMConstPointerCast(f, T_ptr(T_i8()))
423+
}
424+
ty::ty_closure(*) => {
425+
C_struct(~[f, C_null(T_opaque_box_ptr(cx))])
426+
}
427+
_ => {
428+
cx.sess.span_bug(e.span, fmt!(
429+
"unexpected const fn type: %s",
430+
ty_to_str(cx.tcx, ety)))
431+
}
404432
}
405433
}
406434
Some(ast::def_const(def_id)) => {

src/test/run-pass/const-vec-of-fns.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
/*!
12+
* Try to double-check that const fns have the right size (with or
13+
* without dummy env ptr, as appropriate) by iterating a size-2 array.
14+
* If the const size differs from the runtime size, the second element
15+
* should be read as a null or otherwise wrong pointer and crash.
16+
*/
17+
18+
fn f() { }
19+
const bare_fns: &[extern fn()] = &[f, f];
20+
// NOTE Why does this not type without the struct?
21+
struct S(&fn());
22+
const closures: &[S] = &[S(f), S(f)];
23+
24+
pub fn main() {
25+
for bare_fns.each |&bare_fn| { bare_fn() }
26+
for closures.each |&closure| { (*closure)() }
27+
}

0 commit comments

Comments
 (0)