]> git.draconx.ca Git - cdecl99.git/commitdiff
Validate declspecs in function parameters.
authorNick Bowler <nbowler@draconx.ca>
Thu, 7 Jul 2011 00:51:31 +0000 (20:51 -0400)
committerNick Bowler <nbowler@draconx.ca>
Thu, 7 Jul 2011 00:52:11 +0000 (20:52 -0400)
src/parse-decl.c

index b5212ec2d0109da6776c7a2ab348340dcebfd040..c210f7cce52981d96d41bfd2eb9511a63955a49f 100644 (file)
 #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;
        }