aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstrap/all.h2
-rw-r--r--bootstrap/parse.c46
-rw-r--r--bootstrap/test.cff1
-rw-r--r--src/cffc.hff4
-rw-r--r--src/common.hff5
-rw-r--r--src/parse.cff18
6 files changed, 63 insertions, 13 deletions
diff --git a/bootstrap/all.h b/bootstrap/all.h
index 34bab40..1bfe919 100644
--- a/bootstrap/all.h
+++ b/bootstrap/all.h
@@ -30,6 +30,7 @@ struct span {
/* must be alpha sorted */
#define LIST_KEYWORDS(_) \
+ _(alignof) \
_(and) \
_(as) \
_(break) \
@@ -47,6 +48,7 @@ struct span {
_(if) \
_(import) \
_(let) \
+ _(offsetof) \
_(or) \
_(return) \
_(sizeof) \
diff --git a/bootstrap/parse.c b/bootstrap/parse.c
index 0abaf45..31469df 100644
--- a/bootstrap/parse.c
+++ b/bootstrap/parse.c
@@ -907,8 +907,10 @@ structidx2fld(const struct type *ty, int idx) {
}
static int
-structfldnam2idx(const struct type *ty, const char *name) {
+aggfldnam2idx(const struct type *ty, const char *name) {
assert(name);
+ if (ty->t != TYunion && ty->t != TYstruct && ty->t != TYeunion)
+ return -1;
for (int i = 0; i < ty->agg.flds.n; ++i)
if (!strcmp(name, ty->agg.flds.d[i].name))
return i;
@@ -917,7 +919,7 @@ structfldnam2idx(const struct type *ty, const char *name) {
static struct aggfield *
findaggfield(const struct type *ty, const char *name) {
- int i = structfldnam2idx(ty, name);
+ int i = aggfldnam2idx(ty, name);
return i < 0 ? NULL : &ty->agg.flds.d[i];
}
@@ -957,7 +959,7 @@ parsestructini(struct parser *P, const struct type *ty) {
if (lexmatch(P, &tok, '.')) {
const char *fnam = (tok = lexexpect(P, TKident)).str;
lexexpect(P, ':');
- idx = structfldnam2idx(ty, fnam);
+ idx = aggfldnam2idx(ty, fnam);
if (idx < 0)
fatal(P, tok.span, "%s %t has no field `%s'", kind, ty, fnam);
}
@@ -1225,7 +1227,7 @@ pexprimary(struct parser *P) {
ex.span = tok.span;
} else if (lexmatch(P, &tok, TKkw_sizeof)) {
ex.t = Eintlit;
- ex.ty = ty_isize;
+ ex.ty = ty_usize;
if (lexmatch(P, &tok, '(')) {
struct expr exp = parseexpr(P);
ex.i = exp.ty->size;
@@ -1234,6 +1236,40 @@ pexprimary(struct parser *P) {
const struct type *ty = parsetype(P);
ex.i = ty->size;
}
+ } else if (lexmatch(P, &tok, TKkw_alignof)) {
+ ex.t = Eintlit;
+ ex.ty = ty_usize;
+ if (lexmatch(P, &tok, '(')) {
+ struct expr exp = parseexpr(P);
+ ex.i = exp.ty->align;
+ lexexpect(P, ')');
+ } else {
+ const struct type *ty = parsetype(P);
+ ex.i = ty->align;
+ }
+ } else if (lexmatch(P, &tok, TKkw_offsetof)) {
+ lexexpect(P, '(');
+ const struct type *ty = parsetype(P);
+ lexexpect(P, ',');
+ size_t off = 0;
+ for (;;) {
+ const char *name = (tok = lexexpect(P, TKident)).str;
+ struct aggfield *fld = findaggfield(ty, name);
+ if (!fld) {
+ fatal(P, tok.span, "%t has no such field %T", ty, tok);
+ }
+ off += fld->off;
+ ty = fld->ty;
+ if (!lexmatch(P, &tok, '.')) {
+ lexmatch(P, &tok, ',');
+ lexexpect(P, ')');
+ break;
+ }
+ }
+ ex.t = Eintlit;
+ ex.ty = ty_usize;
+ ex.u = off;
+
} else {
experr:
fatal(P, tok.span, "expected expression (near %s)", tok2str(tok));
@@ -1424,7 +1460,7 @@ pexpostfix(struct parser *P) {
bool konst = ty->konst;
ty = unconstify(ty);
if (ty->t == TYstruct || ty->t == TYunion || ty->t == TYeunion) {
- int idx = structfldnam2idx(ty, fnam);
+ int idx = aggfldnam2idx(ty, fnam);
struct aggfield *fld = &ty->agg.flds.d[idx];
if (idx < 0)
fatal(P, tok.span, "%t has no such field `%s'", ty, fnam);
diff --git a/bootstrap/test.cff b/bootstrap/test.cff
index 5e384af..ef0bbfb 100644
--- a/bootstrap/test.cff
+++ b/bootstrap/test.cff
@@ -107,6 +107,7 @@ extern fn main (argc int, argv **u8) int {
printf("sizeof(is) = %zu\n", sizeof(is));
printf("sizeof *void = %zu\n", sizeof *void);
+ printf("alignof f64= %zu\n", alignof f64);
printf("1.2 -> %#.8x\n", transmute(u32, 1.2f));
switch is.#len {
diff --git a/src/cffc.hff b/src/cffc.hff
index d4b0ec1..af5bd6a 100644
--- a/src/cffc.hff
+++ b/src/cffc.hff
@@ -19,10 +19,10 @@ struct Loc {
#[lax]
enum TokT : i32 {
// !sorted
- kw_and, kw_as, kw_break, kw_case, kw_const,
+ kw_alignof, kw_and, kw_as, kw_break, kw_case, kw_const,
kw_continue, kw_def, kw_defmacro, kw_do,
kw_else, kw_enum, kw_extern, kw_fn,
- kw_for, kw_if, kw_import, kw_let,
+ kw_for, kw_if, kw_import, kw_let, kw_offsetof,
kw_or, kw_return, kw_sizeof, kw_static,
kw_struct, kw_switch, kw_typedef, kw_typeof,
kw_union, kw_while,
diff --git a/src/common.hff b/src/common.hff
index 6643dda..187fbf3 100644
--- a/src/common.hff
+++ b/src/common.hff
@@ -52,11 +52,8 @@ defmacro with_tmpchange(var,x,&body) [
defmacro MAX(a,b) [((a) > (b) ? (a) : (b))]
-defmacro offsetof_(T, fld) [
- (as(isize)(&(as(*T)#null).fld))
-]
defmacro container_of(x, T, fld) [
- (as(*T)(as(*void)(x) - offsetof_(T, fld)))
+ (as(*T)(as(*void)(x) - offsetof(T, fld)))
]
// Inline functions
diff --git a/src/parse.cff b/src/parse.cff
index a2071f8..b42d45a 100644
--- a/src/parse.cff
+++ b/src/parse.cff
@@ -141,10 +141,10 @@ fn eatspaces(P *Parser) void {
// !sorted
extern static keyword2str [NUM_KEYWORDS]*const u8 = {
- "and", "as", "break", "case", "const",
+ "alignof", "and", "as", "break", "case", "const",
"continue", "def", "defmacro", "do",
"else", "enum", "extern", "fn",
- "for", "if", "import", "let",
+ "for", "if", "import", "let", "offsetof",
"or", "return", "sizeof", "static",
"struct", "switch", "typedef", "typeof",
"union", "while",
@@ -1152,6 +1152,20 @@ fn pexprimary(P *Parser) Expr {
}
ex = { tok.loc, ty_usize, :IntLit { ty.size }};
+ case :kw_alignof;
+ let ty *const Type #?;
+ if lexmatch(P, &tok, '(') {
+ let ex = parseexpr(P);
+ lexexpect(P, ')');
+ ty = ex.ty;
+ } else {
+ ty = parsetype(P);
+ }
+ if !completetype(ty) {
+ err(P, tok.loc, "alignof incomplete type (%t)", ty);
+ }
+ ex = { tok.loc, ty_usize, :IntLit { ty.align }};
+
case '(';
if lexmatch(P, &tok, :kw_do) {
let st = parseblock0(P);