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...
/*
* Internal declarations for libcdecl.
/*
* 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
*
* 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
-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);
void cdecl__errmsg(unsigned msg);
struct cdecl_declspec *cdecl__normalize_specs(struct cdecl_declspec *specs);
struct parse_item *cdecl__alloc_item(size_t s_sz);
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
+
/*
* Error handling for libcdecl.
/*
* 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
*
* 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
* Sets the library error to code; fmt is a printf-style string that may use
* up to one %s directive, to refer to 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;
{
struct err_state *state;
unsigned try = 0;
+ state->err.code = CDECL_ENOPARSE;
state->err.str = state->str;
state->err.str = state->str;
- state->err.code = code;
}
const struct cdecl_error *cdecl_get_error(void)
}
const struct cdecl_error *cdecl_get_error(void)
%code top {
/*
* Parser for C declarations.
%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
*
* 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
return yytname[YYTRANSLATE(token)];
}
return yytname[YYTRANSLATE(token)];
}
+/*
+ * 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;
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);
c = yytext;
invalid_char:
to_readable_ch(buf, *c);
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);
/*
* Helper application to test internal library error reporting.
/*
* 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
*
* 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
memset(work2, 'X', len - 1);
tap_diag("cdecl__err w/ %lu-byte string", (unsigned long)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();
memset(work1, 0, len);
err = cdecl_get_error();
+ check_code(err, CDECL_ENOPARSE);
errlen = strlen(err->str);
if (!tap_result(errlen == len-1, "returned string length")) {
errlen = strlen(err->str);
if (!tap_result(errlen == len-1, "returned string length")) {
abort();
sprintf(work, fmt, arg);
abort();
sprintf(work, fmt, arg);
- cdecl__err(5432, fmt, arg);
err = cdecl_get_error();
tap_diag("cdecl__err(\"%s\", \"%s\")", fmt, arg);
err = cdecl_get_error();
tap_diag("cdecl__err(\"%s\", \"%s\")", fmt, arg);
+ check_code(err, CDECL_ENOPARSE);
if (!tap_result(!strcmp(err->str, work), "returned string")) {
tap_diag("Failed, unexpected result");
if (!tap_result(!strcmp(err->str, work), "returned string")) {
tap_diag("Failed, unexpected result");
-void cdecl__err(unsigned code, const char *fmt, const char *arg)
+void cdecl__err(const char *fmt, const char *arg)