]> git.draconx.ca Git - cdecl99.git/commitdiff
libcdecl: Fix regression in function parsing.
authorNick Bowler <nbowler@draconx.ca>
Thu, 6 Jul 2023 06:15:35 +0000 (02:15 -0400)
committerNick Bowler <nbowler@draconx.ca>
Fri, 7 Jul 2023 00:27:21 +0000 (20:27 -0400)
Merging the reduce_parentheses and simplify_functions step missed a case
where the function simplification could pull a fake function declarator
up to the current tree position.  Continuing the tree traversal will miss
this, leaving the fake parameter in the tree (which is then rejected as
a syntax error later).

The fix is easy enough, just repeat the whole reduction step until no
changes are needed at the current position before continuing traversal.

Add a new test case that targets this behaviour.

src/parse-decl.c
tests/decl-good.at

index c3ba32db8b3ed177dccf4873b98f61d16d4494da..a6204a18a00c32b524d9bc5dc89cff67cc5b7905 100644 (file)
@@ -230,7 +230,7 @@ simplify_functions(struct cdecl_declarator **p, struct cdecl_declarator *d)
        free(d->child);
        free(d);
 
-       return 0;
+       return 1;
 }
 
 /*
@@ -260,6 +260,9 @@ simplify_functions(struct cdecl_declarator **p, struct cdecl_declarator *d)
  * example, "(((x)))" into "(x)", an abstract function declarator.  The result
  * is then subject to the function simplification step, which will turn "(x)"
  * into x (declaring an identifier).
+ *
+ * The whole process is repeated until no more changes are made to the parse
+ * tree, or a syntax error is detected.
  */
 static struct cdecl *fake_function_param(struct cdecl_declarator *d)
 {
@@ -281,26 +284,28 @@ reduce_parentheses(struct cdecl_declarator **p, struct cdecl_declarator *d)
 {
        struct cdecl *param;
 
-       while ((param = fake_function_param(d))) {
-               struct cdecl_declarator *decl = param->declarators;
-               d->u.function.parameters = NULL;
-
-               if (decl->type != CDECL_DECL_NULL) {
-                       if (d->child->type != CDECL_DECL_NULL) {
-                               /* Found fake parameter on real function. */
-                               d->u.function.parameters = param;
-                               cdecl__errmsg(CDECL__EBADPARAM);
-                               return -1;
+       do {
+               d = *p;
+               while ((param = fake_function_param(d))) {
+                       struct cdecl_declarator *decl = param->declarators;
+                       d->u.function.parameters = NULL;
+
+                       if (decl->type != CDECL_DECL_NULL) {
+                               if (d->child->type != CDECL_DECL_NULL) {
+                                       /* Fake parameter on real function. */
+                                       d->u.function.parameters = param;
+                                       cdecl__errmsg(CDECL__EBADPARAM);
+                                       return -1;
+                               }
+
+                               param->declarators = d;
+                               *p = d = decl;
                        }
 
-                       param->declarators = d;
-                       *p = d = decl;
+                       cdecl__free(param);
                }
+       } while (simplify_functions(p, d));
 
-               cdecl__free(param);
-       }
-
-       simplify_functions(p, d);
        return 0;
 }
 
index 7cd68dba2553bc8c93d1f6ea32339dcf761fd808..230202badd6dac0db39767bbdc28cb1dc860f28d 100644 (file)
@@ -100,3 +100,7 @@ SIMPLE_DECLS_EXPLAIN(
   [[int ((int))], [type function (int) returning int], [int (int)]],
   [[int (x(int))], [declare x as function (int) returning int], [int x(int)]],
   [[int (())], [type function returning int], [int ()]])
+
+SIMPLE_DECLS_EXPLAIN(
+  [[int (x())], [declare x as function returning int], [int x()]],
+  [[int ((x)())], [declare x as function returning int], [int x()]])