Skip to content

Commit b5ceba1

Browse files
committed
librustc: implement a #[packed] attribute for structs.
A struct (inc. tuple struct) can be annotated with #[packed], so that there is no padding between its elements, like GCC's `__attribute__((packed))`. Closes rust-lang#1704.
1 parent c6a4ba9 commit b5ceba1

33 files changed

+217
-138
lines changed

src/librustc/metadata/tydecode.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,9 +387,11 @@ fn parse_ty(st: @mut PState, conv: conv_did) -> ty::t {
387387
'a' => {
388388
assert!((next(st) == '['));
389389
let did = parse_def(st, NominalType, conv);
390+
let packed = next(st) == '1';
391+
assert!((next(st) == '|'));
390392
let substs = parse_substs(st, conv);
391393
assert!((next(st) == ']'));
392-
return ty::mk_struct(st.tcx, did, substs);
394+
return ty::mk_struct(st.tcx, did, substs, packed);
393395
}
394396
c => { error!("unexpected char in type string: %c", c); fail!();}
395397
}

src/librustc/metadata/tyencode.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,14 +328,20 @@ fn enc_sty(w: @io::Writer, cx: @ctxt, +st: ty::sty) {
328328
enc_sigil(w, p);
329329
}
330330
ty::ty_opaque_box => w.write_char('B'),
331-
ty::ty_struct(def, ref substs) => {
331+
ty::ty_struct(def, ref substs, packed) => {
332332
debug!("~~~~ %s", ~"a[");
333333
w.write_str(&"a[");
334334
let s = (cx.ds)(def);
335335
debug!("~~~~ %s", s);
336336
w.write_str(s);
337337
debug!("~~~~ %s", ~"|");
338338
w.write_char('|');
339+
let p = if packed { '1' }
340+
else { '0' };
341+
debug!("~~~~ %c", p);
342+
w.write_char(p);
343+
debug!("~~~~ %s", ~"|");
344+
w.write_char('|');
339345
enc_substs(w, cx, (*substs));
340346
debug!("~~~~ %s", ~"]");
341347
w.write_char(']');

src/librustc/middle/check_match.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ pub fn ctor_arity(cx: @MatchCheckCtxt, ctor: ctor, ty: ty::t) -> uint {
459459
None => fail!(~"impossible case")
460460
}
461461
}
462-
ty::ty_struct(cid, _) => ty::lookup_struct_fields(cx.tcx, cid).len(),
462+
ty::ty_struct(cid, _, _) => ty::lookup_struct_fields(cx.tcx, cid).len(),
463463
ty::ty_unboxed_vec(*) | ty::ty_evec(*) => {
464464
match ctor {
465465
vec(n) => n,
@@ -589,7 +589,7 @@ pub fn specialize(cx: @MatchCheckCtxt,
589589
// Grab the class data that we care about.
590590
let class_fields, class_id;
591591
match ty::get(left_ty).sty {
592-
ty::ty_struct(cid, _) => {
592+
ty::ty_struct(cid, _, _) => {
593593
class_id = cid;
594594
class_fields =
595595
ty::lookup_struct_fields(cx.tcx,

src/librustc/middle/kind.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ fn check_struct_safe_for_destructor(cx: Context,
9696
self_r: None,
9797
self_ty: None,
9898
tps: ~[]
99-
});
99+
}, false); // packed-ness doesn't matter for destructor safety
100100
if !ty::type_is_owned(cx.tcx, struct_ty) {
101101
cx.tcx.sess.span_err(span,
102102
~"cannot implement a destructor on a struct \

src/librustc/middle/mem_categorization.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ pub fn opt_deref_kind(t: ty::t) -> Option<deref_kind> {
188188
Some(deref_comp(comp_variant(did)))
189189
}
190190

191-
ty::ty_struct(_, _) => {
191+
ty::ty_struct(*) => {
192192
Some(deref_comp(comp_anon_field))
193193
}
194194

@@ -1112,7 +1112,7 @@ pub fn field_mutbl(tcx: ty::ctxt,
11121112
-> Option<ast::mutability> {
11131113
// Need to refactor so that struct/enum fields can be treated uniformly.
11141114
match ty::get(base_ty).sty {
1115-
ty::ty_struct(did, _) => {
1115+
ty::ty_struct(did, _, _) => {
11161116
for ty::lookup_struct_fields(tcx, did).each |fld| {
11171117
if fld.ident == f_name {
11181118
let m = match fld.mutability {
@@ -1175,4 +1175,3 @@ pub impl categorization {
11751175
}
11761176
}
11771177
}
1178-

src/librustc/middle/moves.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ pub impl VisitContext {
477477
// then `with` is consumed, otherwise it is only read
478478
let with_ty = ty::expr_ty(self.tcx, *with_expr);
479479
let with_fields = match ty::get(with_ty).sty {
480-
ty::ty_struct(did, ref substs) => {
480+
ty::ty_struct(did, ref substs, _) => {
481481
ty::struct_fields(self.tcx, did, substs)
482482
}
483483
ref r => {

src/librustc/middle/privacy.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ pub fn check_crate(tcx: ty::ctxt,
437437
// allow pointers to violate privacy
438438
match ty::get(ty::type_autoderef(tcx, ty::expr_ty(tcx,
439439
base))).sty {
440-
ty_struct(id, _)
440+
ty_struct(id, _, _)
441441
if id.crate != local_crate ||
442442
!privileged_items.contains(&(id.node)) => {
443443
match method_map.find(&expr.id) {
@@ -462,7 +462,7 @@ pub fn check_crate(tcx: ty::ctxt,
462462
// Ditto
463463
match ty::get(ty::type_autoderef(tcx, ty::expr_ty(tcx,
464464
base))).sty {
465-
ty_struct(id, _)
465+
ty_struct(id, _, _)
466466
if id.crate != local_crate ||
467467
!privileged_items.contains(&(id.node)) => {
468468
match method_map.find(&expr.id) {
@@ -488,7 +488,7 @@ pub fn check_crate(tcx: ty::ctxt,
488488
}
489489
expr_struct(_, ref fields, _) => {
490490
match ty::get(ty::expr_ty(tcx, expr)).sty {
491-
ty_struct(id, _) => {
491+
ty_struct(id, _, _) => {
492492
if id.crate != local_crate ||
493493
!privileged_items.contains(&(id.node)) {
494494
for (*fields).each |field| {
@@ -554,7 +554,7 @@ pub fn check_crate(tcx: ty::ctxt,
554554
match pattern.node {
555555
pat_struct(_, ref fields, _) => {
556556
match ty::get(ty::pat_ty(tcx, pattern)).sty {
557-
ty_struct(id, _) => {
557+
ty_struct(id, _, _) => {
558558
if id.crate != local_crate ||
559559
!privileged_items.contains(&(id.node)) {
560560
for fields.each |field| {
@@ -606,4 +606,3 @@ pub fn check_crate(tcx: ty::ctxt,
606606
});
607607
visit::visit_crate(*crate, method_map, visitor);
608608
}
609-

src/librustc/middle/trans/_match.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1339,7 +1339,7 @@ pub fn compile_submatch(bcx: block,
13391339
let struct_ty = node_id_type(bcx, pat_id);
13401340
let struct_element_count;
13411341
match ty::get(struct_ty).sty {
1342-
ty::ty_struct(struct_id, _) => {
1342+
ty::ty_struct(struct_id, _, _) => {
13431343
struct_element_count =
13441344
ty::lookup_struct_fields(tcx, struct_id).len();
13451345
}

src/librustc/middle/trans/adt.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ pub enum Repr {
8888
struct Struct {
8989
size: u64,
9090
align: u64,
91+
packed: bool,
9192
fields: ~[ty::t]
9293
}
9394

@@ -109,17 +110,18 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
109110
}
110111
let repr = @match ty::get(t).sty {
111112
ty::ty_tup(ref elems) => {
112-
Univariant(mk_struct(cx, *elems), false)
113+
Univariant(mk_struct(cx, *elems, false), false)
113114
}
114-
ty::ty_struct(def_id, ref substs) => {
115+
ty::ty_struct(def_id, ref substs, packed) => {
115116
let fields = ty::lookup_struct_fields(cx.tcx, def_id);
116117
let ftys = do fields.map |field| {
117118
ty::lookup_field_type(cx.tcx, def_id, field.id, substs)
118119
};
119120
let dtor = ty::ty_dtor(cx.tcx, def_id).is_present();
120121
let ftys =
121122
if dtor { ftys + [ty::mk_bool(cx.tcx)] } else { ftys };
122-
Univariant(mk_struct(cx, ftys), dtor)
123+
124+
Univariant(mk_struct(cx, ftys, packed), dtor)
123125
}
124126
ty::ty_enum(def_id, ref substs) => {
125127
struct Case { discr: int, tys: ~[ty::t] };
@@ -132,15 +134,15 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
132134
};
133135
if cases.len() == 0 {
134136
// Uninhabitable; represent as unit
135-
Univariant(mk_struct(cx, ~[]), false)
137+
Univariant(mk_struct(cx, ~[], false), false)
136138
} else if cases.all(|c| c.tys.len() == 0) {
137139
// All bodies empty -> intlike
138140
let discrs = cases.map(|c| c.discr);
139141
CEnum(discrs.min(), discrs.max())
140142
} else if cases.len() == 1 {
141143
// Equivalent to a struct/tuple/newtype.
142144
assert!(cases[0].discr == 0);
143-
Univariant(mk_struct(cx, cases[0].tys), false)
145+
Univariant(mk_struct(cx, cases[0].tys, false), false)
144146
} else {
145147
// The general case. Since there's at least one
146148
// non-empty body, explicit discriminants should have
@@ -151,7 +153,7 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
151153
ty::item_path_str(cx.tcx, def_id)))
152154
}
153155
let discr = ~[ty::mk_int(cx.tcx)];
154-
General(cases.map(|c| mk_struct(cx, discr + c.tys)))
156+
General(cases.map(|c| mk_struct(cx, discr + c.tys, false)))
155157
}
156158
}
157159
_ => cx.sess.bug(~"adt::represent_type called on non-ADT type")
@@ -160,12 +162,13 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
160162
return repr;
161163
}
162164

163-
fn mk_struct(cx: @CrateContext, tys: &[ty::t]) -> Struct {
165+
fn mk_struct(cx: @CrateContext, tys: &[ty::t], packed: bool) -> Struct {
164166
let lltys = tys.map(|&ty| type_of::sizing_type_of(cx, ty));
165-
let llty_rec = T_struct(lltys);
167+
let llty_rec = T_struct(lltys, packed);
166168
Struct {
167169
size: machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64,
168170
align: machine::llalign_of_min(cx, llty_rec) /*bad*/as u64,
171+
packed: packed,
169172
fields: vec::from_slice(tys)
170173
}
171174
}
@@ -358,7 +361,8 @@ fn struct_field_ptr(bcx: block, st: &Struct, val: ValueRef, ix: uint,
358361

359362
let val = if needs_cast {
360363
let real_llty = T_struct(st.fields.map(
361-
|&ty| type_of::type_of(ccx, ty)));
364+
|&ty| type_of::type_of(ccx, ty)),
365+
st.packed);
362366
PointerCast(bcx, val, T_ptr(real_llty))
363367
} else {
364368
val

src/librustc/middle/trans/asm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block {
108108
} else if numOutputs == 1 {
109109
val_ty(outputs[0])
110110
} else {
111-
T_struct(outputs.map(|o| val_ty(*o)))
111+
T_struct(outputs.map(|o| val_ty(*o)), false)
112112
};
113113
114114
let dialect = match ia.dialect {

src/librustc/middle/trans/base.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,7 @@ pub fn get_landing_pad(bcx: block) -> BasicBlockRef {
938938
// The landing pad return type (the type being propagated). Not sure what
939939
// this represents but it's determined by the personality function and
940940
// this is what the EH proposal example uses.
941-
let llretty = T_struct(~[T_ptr(T_i8()), T_i32()]);
941+
let llretty = T_struct(~[T_ptr(T_i8()), T_i32()], false);
942942
// The exception handling personality function. This is the C++
943943
// personality function __gxx_personality_v0, wrapped in our naming
944944
// convention.
@@ -2832,7 +2832,7 @@ pub fn decl_gc_metadata(ccx: @CrateContext, llmod_id: &str) {
28322832
}
28332833
28342834
pub fn create_module_map(ccx: @CrateContext) -> ValueRef {
2835-
let elttype = T_struct(~[ccx.int_type, ccx.int_type]);
2835+
let elttype = T_struct(~[ccx.int_type, ccx.int_type], false);
28362836
let maptype = T_array(elttype, ccx.module_data.len() + 1);
28372837
let map = str::as_c_str(~"_rust_mod_map", |buf| {
28382838
unsafe {
@@ -2872,7 +2872,7 @@ pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta,
28722872
};
28732873
let sym_name = ~"_rust_crate_map_" + mapname;
28742874
let arrtype = T_array(int_type, n_subcrates as uint);
2875-
let maptype = T_struct(~[T_i32(), T_ptr(T_i8()), int_type, arrtype]);
2875+
let maptype = T_struct(~[T_i32(), T_ptr(T_i8()), int_type, arrtype], false);
28762876
let map = str::as_c_str(sym_name, |buf| {
28772877
unsafe {
28782878
llvm::LLVMAddGlobal(llmod, maptype, buf)

src/librustc/middle/trans/cabi_arm.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
1212
use lib::llvm::struct_tys;
1313
use lib::llvm::TypeRef;
1414
use lib::llvm::{Attribute, StructRetAttribute};
15+
use lib::llvm::True;
1516
use middle::trans::cabi::{ABIInfo, FnType, LLVMType};
1617
use middle::trans::common::{T_i8, T_i16, T_i32, T_i64};
1718
use middle::trans::common::{T_array, T_ptr, T_void};
@@ -39,8 +40,12 @@ fn ty_align(ty: TypeRef) -> uint {
3940
Float => 4,
4041
Double => 8,
4142
Struct => {
42-
do vec::foldl(1, struct_tys(ty)) |a, t| {
43-
uint::max(a, ty_align(*t))
43+
if llvm::LLVMIsPackedStruct(ty) == True {
44+
1
45+
} else {
46+
do vec::foldl(1, struct_tys(ty)) |a, t| {
47+
uint::max(a, ty_align(*t))
48+
}
4449
}
4550
}
4651
Array => {
@@ -62,10 +67,16 @@ fn ty_size(ty: TypeRef) -> uint {
6267
Float => 4,
6368
Double => 8,
6469
Struct => {
65-
let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
66-
align(s, *t) + ty_size(*t)
67-
};
68-
align(size, ty)
70+
if llvm::LLVMIsPackedStruct(ty) == True {
71+
do vec::foldl(0, struct_tys(ty)) |s, t| {
72+
s + ty_size(*t)
73+
}
74+
} else {
75+
let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
76+
align(s, *t) + ty_size(*t)
77+
};
78+
align(size, ty)
79+
}
6980
}
7081
Array => {
7182
let len = llvm::LLVMGetArrayLength(ty) as uint;

src/librustc/middle/trans/cabi_mips.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -14,6 +14,7 @@ use core::libc::c_uint;
1414
use lib::llvm::{llvm, TypeRef, Integer, Pointer, Float, Double};
1515
use lib::llvm::{Struct, Array, Attribute};
1616
use lib::llvm::{StructRetAttribute};
17+
use lib::llvm::True;
1718
use middle::trans::common::*;
1819
use middle::trans::cabi::*;
1920

@@ -49,8 +50,12 @@ fn ty_align(ty: TypeRef) -> uint {
4950
Float => 4,
5051
Double => 8,
5152
Struct => {
52-
do vec::foldl(1, struct_tys(ty)) |a, t| {
53-
uint::max(a, ty_align(*t))
53+
if llvm::LLVMIsPackedStruct(ty) == True {
54+
1
55+
} else {
56+
do vec::foldl(1, struct_tys(ty)) |a, t| {
57+
uint::max(a, ty_align(*t))
58+
}
5459
}
5560
}
5661
Array => {
@@ -72,10 +77,16 @@ fn ty_size(ty: TypeRef) -> uint {
7277
Float => 4,
7378
Double => 8,
7479
Struct => {
75-
let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
76-
align(s, *t) + ty_size(*t)
77-
};
78-
align(size, ty)
80+
if llvm::LLVMIsPackedStruct(ty) == True {
81+
do vec::foldl(0, struct_tys(ty)) |s, t| {
82+
s + ty_size(*t)
83+
}
84+
} else {
85+
let size = do vec::foldl(0, struct_tys(ty)) |s, t| {
86+
align(s, *t) + ty_size(*t)
87+
};
88+
align(size, ty)
89+
}
7990
}
8091
Array => {
8192
let len = llvm::LLVMGetArrayLength(ty) as uint;
@@ -174,7 +185,8 @@ fn struct_ty(ty: TypeRef,
174185
fields.push(ty);
175186
}
176187

177-
return T_struct(fields);
188+
// XXX: Is this meant to be always non-packed?
189+
return T_struct(fields, false);
178190
}
179191

180192
enum MIPS_ABIInfo { MIPS_ABIInfo }

0 commit comments

Comments
 (0)