+/*
+ * Function parameters and return types have a few restrictions that are
+ * really easy to check in comparison to the above absurdity.
+ */
+static int
+check_parameters(struct cdecl_declarator **p, struct cdecl_declarator *d)
+{
+ struct cdecl_declspec *spec;
+ struct cdecl *param;
+
+ 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;
+
+ /* Check for "void" function parameters as a special case. */
+ for (spec = param->specifiers; spec; spec = spec->next) {
+ if (param->declarators->type != CDECL_DECL_NULL)
+ continue;
+ if (spec->type != CDECL_TYPE_VOID)
+ continue;
+
+ if (spec != param->specifiers || spec->next != NULL) {
+ cdecl__err(CDECL_EVOIDPARAM, _("void parameter cannot have extra specifiers"));
+ return -1;
+ } else if (d->u.function.parameters->next) {
+ cdecl__err(CDECL_EVOIDPARAM, _("void parameter must stand alone"));
+ return -1;
+ } else if (d->u.function.variadic) {
+ cdecl__err(CDECL_EVOIDPARAM, _("variadic function cannot have void parameter"));
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Functions cannot return arrays or functions. Since the parse tree is
+ * "inside-out", we need to look for functions as the child declarator.
+ */
+static int
+check_rettypes(struct cdecl_declarator **p, struct cdecl_declarator *d)
+{
+ if (!d->child || d->child->type != CDECL_DECL_FUNCTION)
+ return 0;
+
+ switch (d->type) {
+ case CDECL_DECL_FUNCTION:
+ cdecl__err(CDECL_EBADRETURN, _("functions cannot return functions"));
+ return -1;
+ case CDECL_DECL_ARRAY:
+ cdecl__err(CDECL_EBADRETURN, _("functions cannot return arrays"));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+check_arrays(struct cdecl_declarator **p, struct cdecl_declarator *d)
+{
+ if (!d->child || d->child->type != CDECL_DECL_ARRAY)
+ return 0;
+
+ switch (d->type) {
+ case CDECL_DECL_FUNCTION:
+ cdecl__err(CDECL_EBADARRAY, _("array members cannot be functions"));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+normalize_specs(struct cdecl_declarator **p, struct cdecl_declarator *d)
+{
+ struct cdecl_function *func;
+ struct cdecl_pointer *ptr;
+
+ switch (d->type) {
+ case CDECL_DECL_POINTER:
+ ptr = &d->u.pointer;
+ ptr->qualifiers = cdecl__normalize_specs(ptr->qualifiers);
+ break;
+ case CDECL_DECL_FUNCTION:
+ func = &d->u.function;
+ for (struct cdecl *i = func->parameters; i; i = i->next)
+ i->specifiers = cdecl__normalize_specs(i->specifiers);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+check_qualifiers(struct cdecl_declarator **p, struct cdecl_declarator *d)
+{
+ struct cdecl_declspec *spec;
+ struct cdecl_pointer *ptr;
+
+ if (!d->child || d->child->type != CDECL_DECL_POINTER)
+ return 0;
+
+ ptr = &d->child->u.pointer;
+ for (spec = ptr->qualifiers; spec; spec = spec->next) {
+ if (spec->type == CDECL_QUAL_RESTRICT
+ && d->type == CDECL_DECL_FUNCTION) {
+ cdecl__err(CDECL_EBADPOINTER, _("function pointers cannot be restrict-qualified"));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+