]> git.draconx.ca Git - cdecl99.git/commitdiff
libcdecl: Fix parsing of int (x(*)()) etc.
authorNick Bowler <nbowler@draconx.ca>
Fri, 12 Jan 2024 03:50:20 +0000 (22:50 -0500)
committerNick Bowler <nbowler@draconx.ca>
Fri, 12 Jan 2024 05:38:35 +0000 (00:38 -0500)
An incomplete earlier fix for misparsing "int (x*)" didn't correct the
issue for more complex abstract declarators like (*)() or (*)[1][2][3].
The function simplification step is erroneously applied even though
there is no valid parse of "int (x(*)[])" in which x is an identifier
declarator.

In the prior release 1.2, int (x(*)) happens to be parsed correctly but
int (x(*)[]) produces a bogus result.  Since the release, the behaviour
was changed to spit out a syntax error for both, so there is a bit of
regression here.

The randomdecl test rarely generates these so the problem can show up
intermittently.  Add some more conditions so we don't try to simplify
these declarations, and new dedicated test cases to check these.

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

index 8f0bd388a1bcad91f83b23a4676e16652e2ccee8..3c60dd267156580e474f04ee077e8af8af902cdf 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Parse and validate C declarations.
- * Copyright © 2011-2012, 2020-2021, 2023 Nick Bowler
+ * Copyright © 2011-2012, 2020-2021, 2023-2024 Nick Bowler
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -27,6 +27,8 @@
 #include "scan.h"
 #include "errmsg.h"
 
+static struct cdecl *fake_function_param(struct cdecl_declarator *);
+
 /*
  * Allocate a "parse item", which is a union of several parse tree
  * structure types, together with a string buffer.  The s_sz argument
@@ -177,6 +179,36 @@ static bool valid_declspecs(struct cdecl *decl, bool top)
        return true;
 }
 
+/*
+ * Find the tree pointer which leads to the parameter's leaf node.
+ *
+ * Return a null pointer if the traversal locates a syntactic element which
+ * prevents function reduction.  This occurs if the leaf node declares an
+ * identifier, or for nontrivial fake function parameters (see below).
+ */
+static struct cdecl_declarator **leaf_pointer(struct cdecl *param)
+{
+       struct cdecl_declarator *d, **p = &param->declarators;
+
+       if ((param = fake_function_param(param->declarators))) {
+               if (param->declarators->type != CDECL_DECL_NULL)
+                       return NULL; /* e.g. int (x (*)) */
+       }
+
+       while ((d = *p)->child) {
+               p = &d->child;
+
+               if (fake_function_param(d->child))
+                       return NULL; /* e.g. int (x (*)[][1]) */
+       }
+
+       if (d->type != CDECL_DECL_NULL)
+               return NULL; /* e.g. int (x y) */
+
+       return p;
+}
+
+
 /*
  * The C grammar leaves ambiguous some cases where parentheses represent a
  * function declarator or just parentheses.  The language uses additional
@@ -201,13 +233,10 @@ static bool valid_declspecs(struct cdecl *decl, bool top)
 
 static struct cdecl_declarator *reduce_function(struct cdecl *param)
 {
-       struct cdecl_declarator *d, **p = &param->declarators;
        struct parse_item *spec = (void *)param->specifiers;
+       struct cdecl_declarator *d, **p;
 
-       while ((d = *p)->child)
-               p = &d->child;
-
-       if (d->type != CDECL_DECL_NULL)
+       if (!(p = leaf_pointer(param)))
                return NULL;
 
        /*
@@ -260,7 +289,7 @@ simplify_functions(struct cdecl_declarator **p, struct cdecl_declarator *d)
 
        new = reduce_function(d->u.function.parameters);
        if (!new)
-               return 0; /* e.g. int (foo bar) */
+               return 0;
        *p = new;
        free(d);
 
index bb3c16806a8648584d399e61143f2a7f0d007319..f3522559f0217e6113fe9704a63f1946b9e22e53 100644 (file)
@@ -136,6 +136,58 @@ SIMPLE_DECLS(
   [[int (int, b, ...)],  [type function (int, b, ...) returning int]],
   [[int (a, int, ...)],  [type function (a, int, ...) returning int]])
 
+SIMPLE_DECLS(
+  [[[int f(int (*)[])]],
+    [declare f as function (pointer to array of int) returning int]],
+  [[[int f(int (*)[][1])]],
+    [declare f as function (pointer to array of array 1 of int) returning int]],
+  [[[int f(int (*)())]],
+    [declare f as function (pointer to function returning int) returning int]],
+  [[[int f(a (*)[])]],
+    [declare f as function (pointer to array of a) returning int]],
+  [[[int f(a (*)[][1])]],
+    [declare f as function (pointer to array of array 1 of a) returning int]],
+  [[[int f(a (*)())]],
+    [declare f as function (pointer to function returning a) returning int]],
+  [[[int (int (*)[])]],
+    [type function (pointer to array of int) returning int]],
+  [[[int (int (*)[][1])]],
+    [type function (pointer to array of array 1 of int) returning int]],
+  [[[int (int (*)())]],
+    [type function (pointer to function returning int) returning int]],
+  [[[int (a (*)[])]],
+    [type function (pointer to array of a) returning int]],
+  [[[int (a (*)[][1])]],
+    [type function (pointer to array of array 1 of a) returning int]],
+  [[[int (a (*)())]],
+    [type function (pointer to function returning a) returning int]])
+
+SIMPLE_DECLS_EXPLAIN(
+  [[[int f(int ([]))]],
+    [declare f as function (array of int) returning int],
+    [[int f(int [])]]],
+  [[[int f(a ([]))]],
+    [declare f as function (array of a) returning int],
+    [[int f(a [])]]],
+  [[[int f(int (()))]],
+    [declare f as function (function returning int) returning int],
+    [[int f(int ())]]],
+  [[[int f(a (()))]],
+    [declare f as function (function returning a) returning int],
+    [[int f(a ())]]],
+  [[[int (int ([]))]],
+    [type function (array of int) returning int],
+    [[int (int [])]]],
+  [[[int (a ([]))]],
+    [type function (array of a) returning int],
+    [[int (a [])]]],
+  [[[int (int (()))]],
+    [type function (function returning int) returning int],
+    [[int (int ())]]],
+  [[[int (a (()))]],
+    [type function (function returning a) returning int],
+    [[int (a ())]]])
+
 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)]],