]> git.draconx.ca Git - cdecl99.git/commitdiff
libcdecl: Remove error code argument from cdecl__err.
authorNick Bowler <nbowler@draconx.ca>
Tue, 9 Jan 2024 02:21:53 +0000 (21:21 -0500)
committerNick Bowler <nbowler@draconx.ca>
Tue, 9 Jan 2024 04:59:52 +0000 (23:59 -0500)
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
src/error.c
src/parse.y
src/scan.l
t/cdeclerr.c
t/scantest.c

index a1e8a9665b21ebe9593dca36eb25142e35648abe..b586dd45e5b00b7c08d2da83b211cce8f3556293 100644 (file)
@@ -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
index 758f58e63c50d4159195b08189c10cd6467e06c2..a2d705a8d15885f8e8d20986c5f99098a48bb786 100644 (file)
@@ -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)
index c66a803a9e57d66512d186f9f3aa97f2a6b51464..03fa1395a6df02fa27f7ec864998c6251c143388 100644 (file)
@@ -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);
 }
index 73efdde88126075253484ca3d3c760a6959c7019..e720fcf29746c7bc9e75afae37aea5129282c9ce 100644 (file)
@@ -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;
 }
index b4a014ca1e8b2b06fa1c93a0c526007d913eb188..3555d68786c582533b2ebb033dcf4b3b0378d08d 100644 (file)
@@ -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");
index 0a0be2234082349f97f9b5f306bfe36e8fc55485..c8576b1dad98e4bdaba00991cb8cbf010dedf023 100644 (file)
@@ -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)
 {
 }