From 23bee8f66fbd14c308d3c509a59024768bc2feef Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Thu, 11 Jan 2024 22:50:20 -0500 Subject: [PATCH] libcdecl: Fix parsing of int (x(*)()) etc. 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 | 43 +++++++++++++++++++++++++++++++------- tests/decl-good.at | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 7 deletions(-) diff --git a/src/parse-decl.c b/src/parse-decl.c index 8f0bd38..3c60dd2 100644 --- a/src/parse-decl.c +++ b/src/parse-decl.c @@ -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 = ¶m->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 = ¶m->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); diff --git a/tests/decl-good.at b/tests/decl-good.at index bb3c168..f352255 100644 --- a/tests/decl-good.at +++ b/tests/decl-good.at @@ -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)]], -- 2.43.2