diff options
Diffstat (limited to 'expr.c')
-rw-r--r-- | expr.c | 29 |
1 files changed, 22 insertions, 7 deletions
@@ -642,26 +642,41 @@ builtinfunc(struct scope *s, enum builtinkind kind) case BUILTINVAARG: e = mkexpr(EXPRBUILTIN, NULL); e->builtin.kind = BUILTINVAARG; - e->base = exprconvert(assignexpr(s), &typevalistptr); + e->base = mkunaryexpr(TBAND, assignexpr(s)); + if (e->base->base->type != &typevalist) + error(&tok.loc, "va_arg argument must have type va_list"); expect(TCOMMA, "after va_list"); e->type = typename(s, &e->qual); break; case BUILTINVACOPY: - e = mkexpr(EXPRASSIGN, typevalist.base); - e->assign.l = mkunaryexpr(TMUL, exprconvert(assignexpr(s), &typevalistptr)); + e = mkexpr(EXPRASSIGN, &typevoid); + e->assign.l = assignexpr(s); + if (e->assign.l->decayed) + e->assign.l = e->assign.l->base; + if (e->assign.l->type != &typevalist) + error(&tok.loc, "va_copy destination must have type va_list"); expect(TCOMMA, "after target va_list"); - e->assign.r = mkunaryexpr(TMUL, exprconvert(assignexpr(s), &typevalistptr)); - e = exprconvert(e, &typevoid); + e->assign.r = assignexpr(s); + if (e->assign.r->decayed) + e->assign.r = e->assign.r->base; + if (e->assign.r->type != &typevalist) + error(&tok.loc, "va_copy source must have type va_list"); break; case BUILTINVAEND: + e = assignexpr(s); + if (e->decayed) + e = e->base; + if (e->type != &typevalist) + error(&tok.loc, "va_end argument must have type va_list"); e = mkexpr(EXPRBUILTIN, &typevoid); e->builtin.kind = BUILTINVAEND; - exprconvert(assignexpr(s), &typevalistptr); break; case BUILTINVASTART: e = mkexpr(EXPRBUILTIN, &typevoid); e->builtin.kind = BUILTINVASTART; - e->base = exprconvert(assignexpr(s), &typevalistptr); + e->base = mkunaryexpr(TBAND, assignexpr(s)); + if (e->base->base->type != &typevalist) + error(&tok.loc, "va_start argument must have type va_list"); expect(TCOMMA, "after va_list"); param = assignexpr(s); if (param->kind != EXPRIDENT) |