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:
@@ -133,6 +133,7 @@ export type node = struct {
|
||||
next: *node,
|
||||
attr: *node,
|
||||
exported: i32, // bool — `export` keyword present
|
||||
packed: i32, // N_TSTRUCT: `struct @packed` — no padding (harec ast.h:95)
|
||||
type_: *void, // filled in by checker; type.ww treats it as *tinfo
|
||||
tsuffix: str, // typed numeric literal suffix ("i32", "u64", ...)
|
||||
nmod: str, // originating module from `// MODULE: foo`; "" if none
|
||||
@@ -146,7 +147,7 @@ export fn newnode(k: nkind, file: str, line: i32, col: i32) *node = {
|
||||
// fval cast-init: 990's wwdump TK_FLOAT diff requires this file
|
||||
// to tokenise identically through C and ww (lex.ww:382 has the
|
||||
// same workaround for the cstage %g-formats vs ww-skips divergence).
|
||||
let n: *node = alloc(node{kind=k, file=file, line=line, col=col, op=tkind.TK_NONE, str="", uval=0u64, fval=0: f64, lhs=nil, rhs=nil, cond=nil, body=nil, els=nil, list=nil, next=nil, attr=nil, exported=0, type_=nil, tsuffix="", nmod="", usepath="", imported=0})!;
|
||||
let n: *node = alloc(node{kind=k, file=file, line=line, col=col, op=tkind.TK_NONE, str="", uval=0u64, fval=0: f64, lhs=nil, rhs=nil, cond=nil, body=nil, els=nil, list=nil, next=nil, attr=nil, exported=0, packed=0, type_=nil, tsuffix="", nmod="", usepath="", imported=0})!;
|
||||
return n;
|
||||
};
|
||||
|
||||
|
||||
@@ -191,8 +191,21 @@ fn parsetype(p: *parser) *node = {
|
||||
|
||||
if (p.curkind == tkind.TK_STRUCT) {
|
||||
advance(p);
|
||||
expecttok(p, tkind.TK_LBRACE, "expected '{' after struct");
|
||||
let n = newnode(nkind.N_TSTRUCT, pf, pl, pc);
|
||||
// `@packed` is an inline struct TYPE attribute (harec ast.h:95),
|
||||
// after `struct` and before `{` — NOT a fn-decl attr, so it does
|
||||
// not route through parseattrs.
|
||||
if (p.curkind == tkind.TK_AT) {
|
||||
advance(p);
|
||||
let an: str;
|
||||
expectident(p, &an);
|
||||
if (!streq(an, "packed")) {
|
||||
errmsg(p, "unknown struct attribute");
|
||||
} else {
|
||||
n.packed = 1;
|
||||
};
|
||||
};
|
||||
expecttok(p, tkind.TK_LBRACE, "expected '{' after struct");
|
||||
let fhead: *node = nil;
|
||||
let ftail: *node = nil;
|
||||
for (p.curkind != tkind.TK_RBRACE) {
|
||||
|
||||
@@ -144,6 +144,9 @@ export type tinfo = struct {
|
||||
// still lives at slotsize()'s read site;
|
||||
// graduating it here would break `[N]i32`
|
||||
// stride (4*N stays natural).
|
||||
packed: i32, // TY_STRUCT laid out with no padding; part of type
|
||||
// identity (harec types.c:517/621). Mirrors cstage
|
||||
// Type.packed (cmd/wcc/ww.h).
|
||||
};
|
||||
|
||||
// #61 audit §1.8 / Rob+Drew convergence 2026-05-20: memoizes
|
||||
@@ -202,7 +205,7 @@ export type tctx = struct {
|
||||
// ---- constructors -----------------------------------------------------
|
||||
|
||||
export fn newtype(k: tykind) *tinfo = {
|
||||
let t: *tinfo = alloc(tinfo{kind=k, size=0u64, align=0u64, sub=nil, alen=0u64, fields=nil, params=nil, tupleelems=nil, ret=nil, variadic=0, nullable=0, name="", under=nil, slotsize=0u64})!;
|
||||
let t: *tinfo = alloc(tinfo{kind=k, size=0u64, align=0u64, sub=nil, alen=0u64, fields=nil, params=nil, tupleelems=nil, ret=nil, variadic=0, nullable=0, name="", under=nil, slotsize=0u64, packed=0})!;
|
||||
return t;
|
||||
};
|
||||
|
||||
@@ -559,6 +562,9 @@ export fn typeeq(a: *tinfo, b: *tinfo) bool = {
|
||||
return true;
|
||||
};
|
||||
if (k == tykind.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 false; };
|
||||
let fa: *tfield = a.fields;
|
||||
let fb: *tfield = b.fields;
|
||||
for (true) {
|
||||
|
||||
Reference in New Issue
Block a user