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 {

0 commit comments

Comments
 (0)