From 52cf61fd3bf928de5ca56957e5e1a2dc88d10848 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Wed, 30 Jan 2013 15:17:23 -0800 Subject: [PATCH 1/9] Fix const enums better: let them have the same alignment as an "opaque enum". --- src/librustc/middle/trans/consts.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 34f1f1f2314fb..f24ea04569c62 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -470,7 +470,12 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { // FIXME (#1645): enum body alignment is generaly wrong. if !degen { - C_packed_struct(~[discrim, c_args]) + // A packed_struct has an alignment of 1; thus, + // wrapping one around c_args will misalign it the + // same way we normally misalign enum bodies + // without affecting its internal alignment or + // changing the alignment of the enum. + C_struct(~[discrim, C_packed_struct(~[c_args])]) } else if size == 0 { C_struct(~[discrim]) } else { From 877fc8d891e1c710b626281d5312d9a45cbb2226 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Wed, 30 Jan 2013 15:34:52 -0800 Subject: [PATCH 2/9] Pad out enum consts to the expected size; makes enums in tuples work. This is wasted space if the const is just an enum, but optimizing that case without breaking everything else is an issue that can be addressed separately. --- src/librustc/middle/trans/consts.rs | 10 +++++++++- src/test/run-pass/const-enum-tuple.rs | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/const-enum-tuple.rs diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index f24ea04569c62..a9dea596f7df5 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -470,12 +470,20 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { // FIXME (#1645): enum body alignment is generaly wrong. if !degen { + // Pad out the data to the size of its type_of; + // this is necessary if the enum is contained + // within an aggregate (tuple, struct, vector) so + // that the next element is at the right offset. + let actual_size = + machine::llsize_of_real(cx, llvm::LLVMTypeOf(c_args)); + let padding = + C_null(T_array(T_i8(), size - actual_size)); // A packed_struct has an alignment of 1; thus, // wrapping one around c_args will misalign it the // same way we normally misalign enum bodies // without affecting its internal alignment or // changing the alignment of the enum. - C_struct(~[discrim, C_packed_struct(~[c_args])]) + C_struct(~[discrim, C_packed_struct(~[c_args]), padding]) } else if size == 0 { C_struct(~[discrim]) } else { diff --git a/src/test/run-pass/const-enum-tuple.rs b/src/test/run-pass/const-enum-tuple.rs new file mode 100644 index 0000000000000..a55554921c497 --- /dev/null +++ b/src/test/run-pass/const-enum-tuple.rs @@ -0,0 +1,18 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum E { V16(u16), V32(u32) } +const C: (E, u16, u16) = (V16(0xDEAD), 0x600D, 0xBAD); + +fn main() { + let (_, n, _) = C; + assert n != 0xBAD; + assert n == 0x600D; +} From 6cdc283415973c259cfbc869f8c7faed5d4f7e2a Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Wed, 30 Jan 2013 16:08:39 -0800 Subject: [PATCH 3/9] Also need to pad out "C-like" enum consts (paths as well as calls). --- src/librustc/middle/trans/consts.rs | 8 +++++++- src/test/run-pass/const-enum-tuple2.rs | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/const-enum-tuple2.rs diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index a9dea596f7df5..841ffa231d10a 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -434,7 +434,13 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { let lldiscrim = base::get_discrim_val(cx, e.span, enum_did, variant_did); - C_struct(~[lldiscrim]) + // However, we still have to pad it out to the + // size of the full enum; see the expr_call case, + // below. + let ety = ty::expr_ty(cx.tcx, e); + let size = machine::static_size_of_enum(cx, ety); + let padding = C_null(T_array(T_i8(), size)); + C_struct(~[lldiscrim, padding]) } Some(ast::def_struct(_)) => { let ety = ty::expr_ty(cx.tcx, e); diff --git a/src/test/run-pass/const-enum-tuple2.rs b/src/test/run-pass/const-enum-tuple2.rs new file mode 100644 index 0000000000000..c02bdc74cfe44 --- /dev/null +++ b/src/test/run-pass/const-enum-tuple2.rs @@ -0,0 +1,18 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum E { V0, V16(u16) } +const C: (E, u16, u16) = (V0, 0x600D, 0xBAD); + +fn main() { + let (_, n, _) = C; + assert n != 0xBAD; + assert n == 0x600D; +} From 9ad616a10263fab6aed7bfa610bb6cc932936fc1 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Wed, 30 Jan 2013 16:36:07 -0800 Subject: [PATCH 4/9] Make vectors of enums work as constants --- src/librustc/middle/trans/consts.rs | 8 +++++++- src/test/run-pass/const-enum-vector.rs | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/const-enum-vector.rs diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 841ffa231d10a..e68e463ec3470 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -73,9 +73,15 @@ pub fn const_vec(cx: @crate_ctxt, e: @ast::expr, es: &[@ast::expr]) let vec_ty = ty::expr_ty(cx.tcx, e); let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty); let llunitty = type_of::type_of(cx, unit_ty); - let v = C_array(llunitty, es.map(|e| const_expr(cx, *e))); let unit_sz = machine::llsize_of(cx, llunitty); let sz = llvm::LLVMConstMul(C_uint(cx, es.len()), unit_sz); + let vs = es.map(|e| const_expr(cx, *e)); + // If the vector contains enums, an LLVM array won't work. + let v = if vs.any(|vi| val_ty(*vi) != llunitty) { + C_struct(vs) + } else { + C_array(llunitty, vs) + }; return (v, sz, llunitty); } } diff --git a/src/test/run-pass/const-enum-vector.rs b/src/test/run-pass/const-enum-vector.rs new file mode 100644 index 0000000000000..4925d6c0f07df --- /dev/null +++ b/src/test/run-pass/const-enum-vector.rs @@ -0,0 +1,23 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum E { V1(int), V0 } +const C: [E * 3] = [V0, V1(0xDEADBEE), V0]; + +fn main() { + match C[1] { + V1(n) => assert(n == 0xDEADBEE), + _ => die!() + } + match C[2] { + V0 => (), + _ => die!() + } +} From 29b99669dc07d4bec38a791945ecfe8a86294852 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Wed, 30 Jan 2013 16:42:46 -0800 Subject: [PATCH 5/9] Fix pointer consts to work with enums --- src/librustc/middle/trans/consts.rs | 4 +--- src/test/run-pass/const-enum-ptr.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/const-enum-ptr.rs diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index e68e463ec3470..39fcdf405bc92 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -352,10 +352,8 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { } ast::expr_addr_of(ast::m_imm, sub) => { let cv = const_expr(cx, sub); - let subty = ty::expr_ty(cx.tcx, sub), - llty = type_of::type_of(cx, subty); let gv = do str::as_c_str("const") |name| { - llvm::LLVMAddGlobal(cx.llmod, llty, name) + llvm::LLVMAddGlobal(cx.llmod, val_ty(cv), name) }; llvm::LLVMSetInitializer(gv, cv); llvm::LLVMSetGlobalConstant(gv, True); diff --git a/src/test/run-pass/const-enum-ptr.rs b/src/test/run-pass/const-enum-ptr.rs new file mode 100644 index 0000000000000..6ca27fb58b0c2 --- /dev/null +++ b/src/test/run-pass/const-enum-ptr.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum E { V0, V1(int) } +const C: &static/E = &V0; + +fn main() { + match *C { + V0 => (), + _ => die!() + } +} From bbb1202528cf14de4f6b3a4f01c22ab19d64d8e7 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Wed, 30 Jan 2013 16:52:01 -0800 Subject: [PATCH 6/9] Add a test for vstore, which already works --- src/test/run-pass/const-enum-vec-ptr.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/run-pass/const-enum-vec-ptr.rs diff --git a/src/test/run-pass/const-enum-vec-ptr.rs b/src/test/run-pass/const-enum-vec-ptr.rs new file mode 100644 index 0000000000000..a7b0373848080 --- /dev/null +++ b/src/test/run-pass/const-enum-vec-ptr.rs @@ -0,0 +1,23 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum E { V1(int), V0 } +const C: &static/[E] = &[V0, V1(0xDEADBEE), V0]; + +fn main() { + match C[1] { + V1(n) => assert(n == 0xDEADBEE), + _ => die!() + } + match C[2] { + V0 => (), + _ => die!() + } +} From 30aae3d9102c42aacde454620247e5b99c5acfd2 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Wed, 30 Jan 2013 17:51:57 -0800 Subject: [PATCH 7/9] Fix const enum type issues for structs. --- src/librustc/middle/trans/consts.rs | 3 +-- src/test/run-pass/const-enum-struct.rs | 19 +++++++++++++++++++ src/test/run-pass/const-enum-struct2.rs | 19 +++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/const-enum-struct.rs create mode 100644 src/test/run-pass/const-enum-struct2.rs diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 39fcdf405bc92..2f6011e3f6557 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -381,8 +381,7 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { } }) }; - let llty = type_of::type_of(cx, ety); - C_named_struct(llty, [C_struct(cs)]) + C_struct([C_struct(cs)]) } ast::expr_vec(es, ast::m_imm) => { let (v, _, _) = const_vec(cx, e, es); diff --git a/src/test/run-pass/const-enum-struct.rs b/src/test/run-pass/const-enum-struct.rs new file mode 100644 index 0000000000000..463b8452bb8ef --- /dev/null +++ b/src/test/run-pass/const-enum-struct.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum E { V16(u16), V32(u32) } +struct S { a: E, b: u16, c: u16 } +const C: S = S { a: V16(0xDEAD), b: 0x600D, c: 0xBAD }; + +fn main() { + let n = C.b; + assert n != 0xBAD; + assert n == 0x600D; +} diff --git a/src/test/run-pass/const-enum-struct2.rs b/src/test/run-pass/const-enum-struct2.rs new file mode 100644 index 0000000000000..f34549326780e --- /dev/null +++ b/src/test/run-pass/const-enum-struct2.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum E { V0, V16(u16) } +struct S { a: E, b: u16, c: u16 } +const C: S = S { a: V0, b: 0x600D, c: 0xBAD }; + +fn main() { + let n = C.b; + assert n != 0xBAD; + assert n == 0x600D; +} From de8dc026341671b1118d06dd2ada060067448988 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Wed, 30 Jan 2013 23:59:06 -0800 Subject: [PATCH 8/9] Make tuple-like structs containing enums work as constants. --- src/librustc/middle/trans/consts.rs | 6 ++---- src/test/run-pass/const-enum-tuplestruct.rs | 19 +++++++++++++++++++ src/test/run-pass/const-enum-tuplestruct2.rs | 19 +++++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 src/test/run-pass/const-enum-tuplestruct.rs create mode 100644 src/test/run-pass/const-enum-tuplestruct2.rs diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 2f6011e3f6557..0176e5ab32042 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -459,14 +459,12 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { ast::expr_call(callee, args, _) => { match cx.tcx.def_map.find(&callee.id) { Some(ast::def_struct(def_id)) => { - let ety = ty::expr_ty(cx.tcx, e); - let llty = type_of::type_of(cx, ety); let llstructbody = C_struct(args.map(|a| const_expr(cx, *a))); if ty::ty_dtor(cx.tcx, def_id).is_present() { - C_named_struct(llty, ~[ llstructbody, C_u8(0) ]) + C_struct(~[ llstructbody, C_u8(0) ]) } else { - C_named_struct(llty, ~[ llstructbody ]) + C_struct(~[ llstructbody ]) } } Some(ast::def_variant(tid, vid)) => { diff --git a/src/test/run-pass/const-enum-tuplestruct.rs b/src/test/run-pass/const-enum-tuplestruct.rs new file mode 100644 index 0000000000000..d9194ff26b1da --- /dev/null +++ b/src/test/run-pass/const-enum-tuplestruct.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum E { V16(u16), V32(u32) } +struct S(E, u16, u16); +const C: S = S(V16(0xDEAD), 0x600D, 0xBAD); + +fn main() { + let S(_, n, _) = C; + assert n != 0xBAD; + assert n == 0x600D; +} diff --git a/src/test/run-pass/const-enum-tuplestruct2.rs b/src/test/run-pass/const-enum-tuplestruct2.rs new file mode 100644 index 0000000000000..b6d9d01479e13 --- /dev/null +++ b/src/test/run-pass/const-enum-tuplestruct2.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum E { V0, V16(u16) } +struct S(E, u16, u16); +const C: S = S(V0, 0x600D, 0xBAD); + +fn main() { + let S(_, n, _) = C; + assert n != 0xBAD; + assert n == 0x600D; +} From e89d9853a68c684c089d6b9be22b572d9866e580 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Wed, 30 Jan 2013 23:59:50 -0800 Subject: [PATCH 9/9] Fix vector indexing in consts so it works with the enum vector const fix. --- src/librustc/lib/llvm.rs | 1 + src/librustc/middle/trans/consts.rs | 22 +++++++++++--------- src/test/run-pass/const-enum-vec-index.rs | 25 +++++++++++++++++++++++ 3 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 src/test/run-pass/const-enum-vec-index.rs diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 2e3967021c1d3..3a419ac9f59b4 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -382,6 +382,7 @@ pub extern mod llvm { pub unsafe fn LLVMGetUsedValue(U: UseRef) -> ValueRef; /* Operations on Users */ + pub unsafe fn LLVMGetNumOperands(Val: ValueRef) -> c_int; pub unsafe fn LLVMGetOperand(Val: ValueRef, Index: c_uint) -> ValueRef; pub unsafe fn LLVMSetOperand(Val: ValueRef, Index: c_uint, Op: ValueRef); diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 0176e5ab32042..5af62eda1fe4f 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -285,15 +285,17 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { // call. Despite that being "a const", it's not the kind of // const you can ask for the integer-value of, evidently. This // might be an LLVM bug, not sure. In any case, to work around - // this we drop down to the array-type level here and just ask - // how long the array-type itself is, ignoring the length we - // pulled out of the slice. This in turn only works because we - // picked out the original globalvar via const_deref and so can - // recover the array-size of the underlying array, and all this - // will hold together exactly as long as we _don't_ support - // const sub-slices (that is, slices that represent something - // other than a whole array). At that point we'll have more and - // uglier work to do here, but for now this should work. + // this we obtain the initializer and count how many elements it + // has, ignoring the length we pulled out of the slice. (Note + // that the initializer might be a struct rather than an array, + // if enums are involved.) This only works because we picked out + // the original globalvar via const_deref and so can recover the + // array-size of the underlying array (or the element count of + // the underlying struct), and all this will hold together + // exactly as long as we _don't_ support const sub-slices (that + // is, slices that represent something other than a whole + // array). At that point we'll have more and uglier work to do + // here, but for now this should work. // // In the future, what we should be doing here is the // moral equivalent of: @@ -305,7 +307,7 @@ pub fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { // not want to consider sizeof() a constant expression // we can get the value (as a number) out of. - let len = llvm::LLVMGetArrayLength(val_ty(arr)) as u64; + let len = llvm::LLVMGetNumOperands(arr) as u64; let len = match ty::get(bt).sty { ty::ty_estr(*) => {assert len > 0; len - 1}, _ => len diff --git a/src/test/run-pass/const-enum-vec-index.rs b/src/test/run-pass/const-enum-vec-index.rs new file mode 100644 index 0000000000000..b386bbf7f5e76 --- /dev/null +++ b/src/test/run-pass/const-enum-vec-index.rs @@ -0,0 +1,25 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum E { V1(int), V0 } +const C: &[E] = &[V0, V1(0xDEADBEE)]; +const C0: E = C[0]; +const C1: E = C[1]; + +fn main() { + match C0 { + V0 => (), + _ => die!() + } + match C1 { + V1(n) => assert(n == 0xDEADBEE), + _ => die!() + } +}