aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2024-04-15 00:59:32 -0700
committerMichael Forney <mforney@mforney.org>2024-04-15 01:24:32 -0700
commit5f402dadeebe61d82bc809d2017cae46af2cd131 (patch)
tree045fdc6d33021e5ef458b33427f01060add7e7df
parentfc501ceff7fefc6ea2fdd956e2c769fcd11d9fdd (diff)
decl: Support variadic functions with no other parameters
-rw-r--r--decl.c18
-rw-r--r--doc/c23.md7
-rw-r--r--expr.c10
-rw-r--r--qbe.c7
-rw-r--r--test/varargs+aarch64.qbe10
-rw-r--r--test/varargs+riscv64.qbe11
-rw-r--r--test/varargs+x86_64-sysv.c8
-rw-r--r--test/varargs+x86_64-sysv.qbe10
8 files changed, 63 insertions, 18 deletions
diff --git a/decl.c b/decl.c
index 96428ba..a9ee504 100644
--- a/decl.c
+++ b/decl.c
@@ -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;
diff --git a/doc/c23.md b/doc/c23.md
index 1c555b4..a8a50e3 100644
--- a/doc/c23.md
+++ b/doc/c23.md
@@ -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
diff --git a/expr.c b/expr.c
index 22fd242..fb6c144 100644
--- a/expr.c
+++ b/expr.c
@@ -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");
diff --git a/qbe.c b/qbe.c
index 13643dc..e98e6fe 100644
--- a/qbe.c
+++ b/qbe.c
@@ -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
+}