parse,check,type,wwi: @packed struct attribute, both stages (#51)
Hare/harec @packed struct layout: no inter-field or trailing padding, align =
max field align (NOT forced to 1) — matches harec type_store.c + types.c:621
(packed{u8,u64}=size 9/align 8). Parser consumes inline @packed (loud-rejects
unknown struct attrs, both stages); layout gates padding on !packed; cstage
type_eq enforces packed type-distinctness; the .wwi producer round-trips
"struct @packed {". wwstage sets slotsize=size for packed so its composite-ABI
copy matches cstage byte-for-byte. cstage identity is faithful; wwstage identity
rides the deferred #224 nominal-resolvealias arc (#108). Both stages byte-id;
447 tests pass.
This commit is contained in:
@@ -252,7 +252,9 @@ wwi_type(FILE *of, Node *t)
|
||||
wwi_type(of, t->lhs);
|
||||
break;
|
||||
case N_TSTRUCT:
|
||||
fputs("struct { ", of);
|
||||
/* re-emit the `@packed` attr so the flag round-trips
|
||||
* through sep-compile (harec unparse/type.ha:122-126). */
|
||||
fputs(t->packed ? "struct @packed { " : "struct { ", of);
|
||||
for (Node *f = t->list; f; f = f->next) {
|
||||
if (f != t->list) fputs(", ", of);
|
||||
if (f->str && f->str[0]) {
|
||||
|
||||
@@ -935,7 +935,11 @@ resolve_type(Checker *c, Node *n)
|
||||
if (!require_sized(c, ft, f->pos, "a struct field"))
|
||||
continue;
|
||||
if (ft->align > maxalign) maxalign = ft->align;
|
||||
off = (off + ft->align - 1) & ~(ft->align - 1);
|
||||
/* packed: no inter-field padding (harec
|
||||
* type_store.c:206-213); align still tracks the
|
||||
* max field align below. */
|
||||
if (!n->packed)
|
||||
off = (off + ft->align - 1) & ~(ft->align - 1);
|
||||
if (f->str != NULL) {
|
||||
/* regular named field */
|
||||
for (Tfield *e = head; e; e = e->next)
|
||||
@@ -985,8 +989,12 @@ resolve_type(Checker *c, Node *n)
|
||||
off = base + inner->size;
|
||||
}
|
||||
t->fields = head;
|
||||
t->packed = n->packed;
|
||||
t->align = maxalign;
|
||||
t->size = (off + maxalign - 1) & ~(maxalign - 1);
|
||||
/* packed: skip the trailing pad-to-align (harec
|
||||
* type_store.c:886 `!packed`); align value unchanged. */
|
||||
t->size = n->packed ? off
|
||||
: ((off + maxalign - 1) & ~(maxalign - 1));
|
||||
return t;
|
||||
}
|
||||
case N_TENUM: {
|
||||
|
||||
@@ -204,8 +204,25 @@ parsetype(Parser *p)
|
||||
}
|
||||
case TK_STRUCT: {
|
||||
advance(p);
|
||||
expect(p, TK_LBRACE);
|
||||
Node *n = newnode(p->a, N_TSTRUCT, pp);
|
||||
/* `@packed` is an inline struct TYPE attribute (harec
|
||||
* ast.h:95 `bool packed`), sitting after `struct` and
|
||||
* before `{` — NOT a fn-decl attr, so it does not route
|
||||
* through parseattrs. */
|
||||
if (p->cur.kind == TK_AT) {
|
||||
advance(p);
|
||||
const char *an = expectident(p);
|
||||
/* p->errs gates the build (cmd/w6c/main.c:82);
|
||||
* nerrors is advisory-only, so an errorf on a
|
||||
* clean-recovery path must bump p->errs itself. */
|
||||
if (strcmp(an, "packed") != 0) {
|
||||
errorf(p->cur.pos,
|
||||
"unknown struct attribute '@%s'", an);
|
||||
p->errs++;
|
||||
} else
|
||||
n->packed = 1;
|
||||
}
|
||||
expect(p, TK_LBRACE);
|
||||
Node *head = NULL, *tail = NULL;
|
||||
while (p->cur.kind != TK_RBRACE && p->cur.kind != TK_EOF) {
|
||||
Pos fp = p->cur.pos;
|
||||
|
||||
@@ -267,6 +267,9 @@ type_eq(Type *a, Type *b)
|
||||
return pa == NULL && pb == NULL;
|
||||
}
|
||||
case TY_STRUCT: {
|
||||
/* packed is part of struct identity: a packed struct is
|
||||
* not equal to its unpacked twin (harec types.c:621). */
|
||||
if (a->packed != b->packed) return 0;
|
||||
Tfield *fa = a->fields, *fb = b->fields;
|
||||
while (fa && fb) {
|
||||
if (strcmp(fa->name, fb->name) != 0) return 0;
|
||||
|
||||
@@ -345,6 +345,8 @@ struct Node {
|
||||
Node *next; /* sibling link inside `list` */
|
||||
Node *attr; /* @attribute chain (N_ATTR list) */
|
||||
int export;
|
||||
int packed; /* N_TSTRUCT: `struct @packed` — no field/
|
||||
* trailing padding (harec ast.h:95). */
|
||||
Type *type; /* filled in by checker */
|
||||
const char *tsuffix; /* typed numeric literal suffix */
|
||||
const char *module; /* `// MODULE: foo` directive at the
|
||||
@@ -487,6 +489,8 @@ struct Type {
|
||||
* stored as a single 8-byte pointer; null
|
||||
* is the void variant. Mirrors Hare's
|
||||
* `(*T | null)` folding. */
|
||||
int packed; /* TY_STRUCT laid out with no padding; part
|
||||
* of type identity (harec types.c:517/621). */
|
||||
};
|
||||
|
||||
extern Type *ty_void, *ty_bool, *ty_rune;
|
||||
|
||||
Reference in New Issue
Block a user