From: Nick Bowler Date: Thu, 6 Jul 2023 06:15:35 +0000 (-0400) Subject: libcdecl: Fix regression in function parsing. X-Git-Tag: v1.3~129 X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/commitdiff_plain/bcde46a8503359755ca72fe581a18f7a3bcaaf37 libcdecl: Fix regression in function parsing. 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. --- diff --git a/src/parse-decl.c b/src/parse-decl.c index c3ba32d..a6204a1 100644 --- a/src/parse-decl.c +++ b/src/parse-decl.c @@ -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; } diff --git a/tests/decl-good.at b/tests/decl-good.at index 7cd68db..230202b 100644 --- a/tests/decl-good.at +++ b/tests/decl-good.at @@ -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()]])