cproc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/cproc
Log | Files | Refs | Submodules | README | LICENSE

commit 2833c0041d669bc1ba7a6d13e7f92c23b84e04ae
parent 88aa3b6891678669548f01a0f87c36a993694320
Author: Michael Forney <mforney@mforney.org>
Date:   Wed, 17 Apr 2019 15:07:39 -0700

Allow designators in __builtin_offsetof

Diffstat:
Mexpr.c | 41++++++++++++++++++++++++++++++++++++++++-
Atest/builtin-offsetof.c | 9+++++++++
Atest/builtin-offsetof.qbe | 1+
3 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/expr.c b/expr.c @@ -400,11 +400,48 @@ primaryexpr(struct scope *s) static struct expr *condexpr(struct scope *); +/* TODO: merge with init.c:designator() */ +static void +designator(struct scope *s, struct type *t, uint64_t *offset) +{ + char *name; + struct member *m; + uint64_t i; + + for (;;) { + switch (tok.kind) { + case TLBRACK: + if (t->kind != TYPEARRAY) + error(&tok.loc, "index designator is only valid for array types"); + next(); + i = intconstexpr(s, false); + expect(TRBRACK, "for index designator"); + t = t->base; + *offset += i * t->size; + break; + case TPERIOD: + if (t->kind != TYPESTRUCT && t->kind != TYPEUNION) + error(&tok.loc, "member designator only valid for struct/union types"); + next(); + name = expect(TIDENT, "for member designator"); + m = typemember(t, name, offset); + if (!m) + error(&tok.loc, "%s has no member named '%s'", t->kind == TYPEUNION ? "union" : "struct", name); + free(name); + t = m->type; + break; + default: + return; + } + } +} + static struct expr * builtinfunc(struct scope *s, enum builtinkind kind) { struct expr *e, *param; struct type *t; + struct member *m; char *name; uint64_t offset; @@ -437,8 +474,10 @@ builtinfunc(struct scope *s, enum builtinkind kind) if (t->kind != TYPESTRUCT && t->kind != TYPEUNION) error(&tok.loc, "type is not a struct/union type"); offset = 0; - if (!typemember(t, name, &offset)) + m = typemember(t, name, &offset); + if (!m) error(&tok.loc, "struct/union has no member named '%s'", name); + designator(s, m->type, &offset); e = mkconstexpr(&typeulong, offset); free(name); break; diff --git a/test/builtin-offsetof.c b/test/builtin-offsetof.c @@ -0,0 +1,9 @@ +struct s { + struct { + union { + float z; + char *c; + } b; + } a[5]; +}; +int x = __builtin_offsetof(struct s, a[2].b.c); diff --git a/test/builtin-offsetof.qbe b/test/builtin-offsetof.qbe @@ -0,0 +1 @@ +export data $x = align 4 { w 16, }