diff options
author | Michael Forney <mforney@mforney.org> | 2024-04-15 00:59:32 -0700 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2024-04-15 01:24:32 -0700 |
commit | 5f402dadeebe61d82bc809d2017cae46af2cd131 (patch) | |
tree | 045fdc6d33021e5ef458b33427f01060add7e7df | |
parent | fc501ceff7fefc6ea2fdd956e2c769fcd11d9fdd (diff) |
decl: Support variadic functions with no other parameters
-rw-r--r-- | decl.c | 18 | ||||
-rw-r--r-- | doc/c23.md | 7 | ||||
-rw-r--r-- | expr.c | 10 | ||||
-rw-r--r-- | qbe.c | 7 | ||||
-rw-r--r-- | test/varargs+aarch64.qbe | 10 | ||||
-rw-r--r-- | test/varargs+riscv64.qbe | 11 | ||||
-rw-r--r-- | test/varargs+x86_64-sysv.c | 8 | ||||
-rw-r--r-- | test/varargs+x86_64-sysv.qbe | 10 |
8 files changed, 63 insertions, 18 deletions
@@ -604,20 +604,21 @@ declaratortypes(struct scope *s, struct list *result, char **name, struct scope t->u.func.nparam = 0; paramend = &t->u.func.params; s = mkscope(s); - while (tok.kind != TRPAREN) { + do { + if (consume(TELLIPSIS)) { + t->u.func.isvararg = true; + break; + } + if (tok.kind == TRPAREN) + break; d = parameter(s); if (d->name) scopeputdecl(s, d); *paramend = d; paramend = &d->next; ++t->u.func.nparam; - if (!consume(TCOMMA)) - break; - if (consume(TELLIPSIS)) { - t->u.func.isvararg = true; - break; - } - } + } while (consume(TCOMMA)); + expect(TRPAREN, "to close function declarator"); if (funcscope && ptr->prev == prev) { /* we may need to re-open the scope later if this is a function definition */ *funcscope = s; @@ -629,7 +630,6 @@ declaratortypes(struct scope *s, struct list *result, char **name, struct scope t->u.func.params = NULL; t->u.func.nparam = 0; } - expect(TRPAREN, "to close function declarator"); listinsert(ptr->prev, &t->link); allowattr = true; break; @@ -50,6 +50,12 @@ with `typeof` to specify that same type. C23 also introduces `typeof_unqual`, which behaves the same as `typeof` except that the specified type is unqualified. +## [N2975]: Relax requirements for variadic parameter lists + +C23 allows variadic functions with no named parameters. The second +argument to the va_arg macro is now optional and is only used for +backwards compatibility. + ## [N3029]: Improved Normal Enumerations C23 allows enumerators outside the range of `int`. When an enum @@ -79,5 +85,6 @@ used inside the enum. [N2549]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2549.pdf [N2900]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2900.htm [N2927]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2927.htm +[N2975]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2975.pdf [N3029]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3029.htm [N3030]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3030.htm @@ -773,7 +773,7 @@ designator(struct scope *s, struct type *t, unsigned long long *offset) static struct expr * builtinfunc(struct scope *s, enum builtinkind kind) { - struct expr *e, *param; + struct expr *e; struct type *t; struct member *m; char *name; @@ -868,12 +868,8 @@ builtinfunc(struct scope *s, enum builtinkind kind) error(&tok.loc, "va_start argument must have type va_list"); if (typeadjvalist == targ->typevalist) e->base = mkunaryexpr(TBAND, e->base); - expect(TCOMMA, "after va_list"); - param = assignexpr(s); - if (param->kind != EXPRIDENT) - error(&tok.loc, "expected parameter identifier"); - delexpr(param); - /* XXX: check that this was actually a parameter name? */ + if (consume(TCOMMA)) + delexpr(assignexpr(s)); break; default: fatal("internal error; unknown builtin"); @@ -1219,8 +1219,11 @@ emitfunc(struct func *f, bool global) putchar(' '); emitvalue(v); } - if (f->type->u.func.isvararg) - fputs(", ...", stdout); + if (f->type->u.func.isvararg) { + if (f->type->u.func.params) + fputs(", ", stdout); + fputs("...", stdout); + } puts(") {"); for (b = f->start; b; b = b->next) { emitvalue(&b->label); diff --git a/test/varargs+aarch64.qbe b/test/varargs+aarch64.qbe index 5b6e830..c444c85 100644 --- a/test/varargs+aarch64.qbe +++ b/test/varargs+aarch64.qbe @@ -45,3 +45,13 @@ function $f3(w %.1, ...) { @while_join.9 ret } +export +function $f4(...) { +@start.10 + %.1 =l alloc8 32 +@body.11 + vastart %.1 + %.2 =d vaarg %.1 + %.3 =w vaarg %.1 + ret +} diff --git a/test/varargs+riscv64.qbe b/test/varargs+riscv64.qbe index 48638bb..1b0851e 100644 --- a/test/varargs+riscv64.qbe +++ b/test/varargs+riscv64.qbe @@ -49,3 +49,14 @@ function $f3(w %.1, ...) { %.10 =l loadl %.3 ret } +export +function $f4(...) { +@start.10 + %.1 =l alloc8 8 +@body.11 + vastart %.1 + %.2 =d vaarg %.1 + %.3 =w vaarg %.1 + %.4 =l loadl %.1 + ret +} diff --git a/test/varargs+x86_64-sysv.c b/test/varargs+x86_64-sysv.c index 71bf1d3..dfa1b98 100644 --- a/test/varargs+x86_64-sysv.c +++ b/test/varargs+x86_64-sysv.c @@ -24,3 +24,11 @@ void f3(int n, ...) { } __builtin_va_end(ap); } + +void f4(...) { + __builtin_va_list ap; + __builtin_va_start(ap); + __builtin_va_arg(ap, double); + __builtin_va_arg(ap, int); + __builtin_va_end(ap); +} diff --git a/test/varargs+x86_64-sysv.qbe b/test/varargs+x86_64-sysv.qbe index 46904b6..4fa8e7b 100644 --- a/test/varargs+x86_64-sysv.qbe +++ b/test/varargs+x86_64-sysv.qbe @@ -47,3 +47,13 @@ function $f3(w %.1, ...) { @while_join.9 ret } +export +function $f4(...) { +@start.10 + %.1 =l alloc8 24 +@body.11 + vastart %.1 + %.2 =d vaarg %.1 + %.3 =w vaarg %.1 + ret +} |