From e9d3a59c29b3eea45ea37bc3ceef5d32ed81b9eb Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Mon, 8 Jan 2024 21:21:53 -0500 Subject: [PATCH] libcdecl: Remove error code argument from cdecl__err. All callers of this internal function use the same error code (CDECL__ENOPARSE), so removing this from the internal interface can save a little bit of code. Or at least it would except that this simplification makes GCC decide to inline yyerror in the parser, which has a significantly worse opposite effect. It's not so pretty, but let's mark yyerror "noinline" as a workaround so that deleting this code actually results in less code... --- src/cdecl-internal.h | 21 +++++++++++++++++++-- src/error.c | 6 +++--- src/parse.y | 11 ++++++++--- src/scan.l | 2 +- t/cdeclerr.c | 10 +++++----- t/scantest.c | 2 +- 6 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/cdecl-internal.h b/src/cdecl-internal.h index a1e8a96..b586dd4 100644 --- a/src/cdecl-internal.h +++ b/src/cdecl-internal.h @@ -1,6 +1,6 @@ /* * Internal declarations for libcdecl. - * Copyright © 2021, 2023 Nick Bowler + * Copyright © 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 @@ -70,7 +70,7 @@ static inline void cdecl__init_i18n(void) } #endif -void cdecl__err(unsigned code, const char *fmt, const char *arg); +void cdecl__err(const char *fmt, const char *arg); void cdecl__errmsg(unsigned msg); struct cdecl_declspec *cdecl__normalize_specs(struct cdecl_declspec *specs); @@ -117,4 +117,21 @@ struct parse_item { struct parse_item *cdecl__alloc_item(size_t s_sz); +/* + * GCC enables -finline-small-functions in most optimization modes; this works + * on a highlevel estimate of how big a function actually is and occasionally + * this produces really bad results. + * + * While old versions of GCC do not support this attribute the result seems + * to be merely a warning so hopefully we can get away with this check and + * save a configure test. + */ +#ifndef CDECL__NOINLINE +# if __GNUC__ +# define CDECL__NOINLINE __attribute__((__noinline__)) +# else +# define CDECL__NOINLINE /**/ +# endif +#endif + #endif diff --git a/src/error.c b/src/error.c index 758f58e..a2d705a 100644 --- a/src/error.c +++ b/src/error.c @@ -1,6 +1,6 @@ /* * Error handling for libcdecl. - * Copyright © 2011-2012, 2021, 2023 Nick Bowler + * Copyright © 2011-2012, 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 @@ -167,7 +167,7 @@ fmt_err(struct err_state *state, const char *fmt, const char *arg) * Sets the library error to code; fmt is a printf-style string that may use * up to one %s directive, to refer to arg. */ -void cdecl__err(unsigned code, const char *fmt, const char *arg) +void cdecl__err(const char *fmt, const char *arg) { struct err_state *state; unsigned try = 0; @@ -189,8 +189,8 @@ retry: goto retry; } + state->err.code = CDECL_ENOPARSE; state->err.str = state->str; - state->err.code = code; } const struct cdecl_error *cdecl_get_error(void) diff --git a/src/parse.y b/src/parse.y index c66a803..03fa139 100644 --- a/src/parse.y +++ b/src/parse.y @@ -1,7 +1,7 @@ %code top { /* * Parser for C declarations. - * Copyright © 2011-2012, 2021, 2023 Nick Bowler + * Copyright © 2011-2012, 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 @@ -618,11 +618,16 @@ const char *cdecl__token_name(unsigned token) return yytname[YYTRANSLATE(token)]; } -static void +/* + * Current versions of GCC (up to 13) want to inline this function into the + * parser even when optimizing for size and the results are not great, so + * try to prevent such inlining. + */ +CDECL__NOINLINE static void yyerror(YYLTYPE *loc, yyscan_t scanner, struct cdecl **out, const char *err) { if (strstr(err, yytname[YYTRANSLATE(T_LEX_ERROR)])) return; - cdecl__err(CDECL_ENOPARSE, "%s", err); + cdecl__err("%s", err); } diff --git a/src/scan.l b/src/scan.l index 73efdde..e720fcf 100644 --- a/src/scan.l +++ b/src/scan.l @@ -231,6 +231,6 @@ int_parse: c = yytext; invalid_char: to_readable_ch(buf, *c); - cdecl__err(CDECL_ENOPARSE, _("syntax error, unexpected %s"), buf); + cdecl__err(_("syntax error, unexpected %s"), buf); return T_LEX_ERROR; } diff --git a/t/cdeclerr.c b/t/cdeclerr.c index b4a014c..3555d68 100644 --- a/t/cdeclerr.c +++ b/t/cdeclerr.c @@ -1,6 +1,6 @@ /* * Helper application to test internal library error reporting. - * Copyright © 2023 Nick Bowler + * Copyright © 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 @@ -83,11 +83,11 @@ static void check_fixed_string(size_t len) memset(work2, 'X', len - 1); tap_diag("cdecl__err w/ %lu-byte string", (unsigned long)len); - cdecl__err(1234, work1, "XX"); + cdecl__err(work1, "XX"); memset(work1, 0, len); err = cdecl_get_error(); - check_code(err, 1234); + check_code(err, CDECL_ENOPARSE); errlen = strlen(err->str); if (!tap_result(errlen == len-1, "returned string length")) { @@ -124,11 +124,11 @@ static void check_format_string(const char *fmt, const char *arg) abort(); sprintf(work, fmt, arg); - cdecl__err(5432, fmt, arg); + cdecl__err(fmt, arg); err = cdecl_get_error(); tap_diag("cdecl__err(\"%s\", \"%s\")", fmt, arg); - check_code(err, 5432); + check_code(err, CDECL_ENOPARSE); if (!tap_result(!strcmp(err->str, work), "returned string")) { tap_diag("Failed, unexpected result"); diff --git a/t/scantest.c b/t/scantest.c index 0a0be22..c8576b1 100644 --- a/t/scantest.c +++ b/t/scantest.c @@ -38,7 +38,7 @@ void cdecl__errmsg(unsigned msg) { } -void cdecl__err(unsigned code, const char *fmt, const char *arg) +void cdecl__err(const char *fmt, const char *arg) { } -- 2.43.2