#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;
}
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;
}
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;
}
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
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;
}