From: Nick Bowler Date: Thu, 7 Jul 2011 00:51:31 +0000 (-0400) Subject: Validate declspecs in function parameters. X-Git-Tag: v1~146 X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/commitdiff_plain/34d65b55a47f66bb907d30ae2b65c4fb64f38cc5 Validate declspecs in function parameters. --- diff --git a/src/parse-decl.c b/src/parse-decl.c index b5212ec..c210f7c 100644 --- a/src/parse-decl.c +++ b/src/parse-decl.c @@ -25,9 +25,11 @@ #include "scan.h" /* - * Verify the declaration specifiers of a declaration. + * Verify the declaration specifiers of a declaration. If top is true, treat + * this as a top-level declaration. Otherwise, treat this as a function + * parameter (which carries additional constraints). */ -static bool valid_declspecs(struct cdecl *decl) +static bool valid_declspecs(struct cdecl *decl, bool top) { struct cdecl_declspec *specs = decl->specifiers; struct cdecl_declarator *d = decl->declarators; @@ -49,6 +51,11 @@ static bool valid_declspecs(struct cdecl *decl) } continue; case CDECL_SPEC_STOR: + if (!top && c->type != CDECL_STOR_REGISTER) { + fprintf(stderr, "function parameters may only have register storage\n"); + return false; + } + if (++num_storage > 1) { fprintf(stderr, "too many storage-class specifiers\n"); return false; @@ -65,7 +72,7 @@ static bool valid_declspecs(struct cdecl *decl) } break; case CDECL_SPEC_FUNC: - if (d->type != CDECL_DECL_FUNCTION) { + if (!top || d->type != CDECL_DECL_FUNCTION) { fprintf(stderr, "only function declarations may have function specifiers.\n"); return false; } @@ -244,6 +251,38 @@ reduce_parentheses(struct cdecl_declarator **p, struct cdecl_declarator *d) return 0; } +static int +check_parameters(struct cdecl_declarator **p, struct cdecl_declarator *d) +{ + struct cdecl_declspec *spec; + struct cdecl *param; + bool has_void = false; + + if (d->type != CDECL_DECL_FUNCTION) + return 0; + + for (param = d->u.function.parameters; param; param = param->next) { + if (!valid_declspecs(param, false)) + return -1; + + for (spec = param->specifiers; spec; spec = spec->next) { + if (spec->type == CDECL_TYPE_VOID + && param->declarators->type == CDECL_DECL_NULL) + has_void = true; + } + } + + if (has_void && d->u.function.parameters->next) { + fprintf(stderr, "a void parameter must stand alone\n"); + return -1; + } else if (has_void && d->u.function.variadic) { + fprintf(stderr, "variadic functions cannot have a void parameter\n"); + return -1; + } + + return 0; +} + /* * Traverse the parse tree, calling a function on every declarator in a * depth-first preorder traversal. The function is given a pointer to the @@ -299,8 +338,10 @@ struct cdecl *cdecl_parse_decl(const char *declstr) goto err; if (!forall_declarators(i, simplify_functions)) goto err; + if (!forall_declarators(i, check_parameters)) + goto err; - if (!valid_declspecs(i)) + if (!valid_declspecs(i, true)) goto err; }