Skip to content

Commit af92398

Browse files
committed
diagnostics: report useless actions
In order for the useless chain productions to work properly, there should not be actions that make explicit the default behavior. * src/scan-code.l (strspacecmp, useless_default_action): New. (translate_action): Report useless actions. * src/reader.c (grammar_rule_check_and_complete): Don't trigger this warning when generating explicit actions for C++. * tests/actions.at (Useless default actions): New.
1 parent e445f99 commit af92398

File tree

3 files changed

+121
-4
lines changed

3 files changed

+121
-4
lines changed

src/reader.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,10 @@ grammar_rule_check_and_complete (symbol_list *r)
307307
|| STREQ (skeleton, "lalr1.cc")));
308308
if (is_cxx)
309309
{
310-
code_props_rule_action_init (&r->action_props, "{ $$ = $1; }",
310+
/* Parens around $1 to avoid triggering the warning
311+
about useless explicit actions. */
312+
code_props_rule_action_init (&r->action_props,
313+
"{ $$ = ($1); }",
311314
r->rhs_loc, r,
312315
/* name */ NULL,
313316
/* type */ NULL,

src/scan-code.l

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <quote.h>
2727

2828
#include <src/complain.h>
29+
#include <src/fixits.h>
2930
#include <src/getargs.h>
3031
#include <src/muscle-tab.h>
3132
#include <src/reader.h>
@@ -289,9 +290,9 @@ variant_add (uniqstr id, location id_loc, unsigned symbol_index,
289290
char const *cp, char const *cp_end, bool explicit_bracketing)
290291
{
291292
char const *prefix_end = find_prefix_end (id, cp, cp_end);
292-
if (prefix_end &&
293-
(prefix_end == cp_end ||
294-
(!explicit_bracketing && is_dot_or_dash (*prefix_end))))
293+
if (prefix_end
294+
&& (prefix_end == cp_end
295+
|| (!explicit_bracketing && is_dot_or_dash (*prefix_end))))
295296
{
296297
variant *r = variant_table_grow ();
297298
r->symbol_index = symbol_index;
@@ -743,6 +744,70 @@ handle_action_at (symbol_list *rule, char *text, location at_loc)
743744
}
744745

745746

747+
/* Comparing two strings, ignoring spaces. */
748+
static int
749+
strspacecmp (const char *cp1, const char* cp2)
750+
{
751+
aver (cp1 && cp2);
752+
while (*cp1 && *cp2)
753+
{
754+
while (c_isspace (*cp1))
755+
++cp1;
756+
while (c_isspace (*cp2))
757+
++cp2;
758+
if (*cp1 == *cp2)
759+
{
760+
++cp1;
761+
++cp2;
762+
}
763+
else
764+
break;
765+
}
766+
return *cp1 - *cp2;
767+
}
768+
769+
/* Whether this rule could have been left implicit.
770+
771+
A more natural place for this check is
772+
grammar_rule_check_and_complete, but it is called after the action
773+
was translated. Maybe we should compare translated code
774+
instead? */
775+
776+
static bool
777+
useless_default_action (code_props *self)
778+
{
779+
/* Somewhat duplicates a part of grammar_rule_check_and_complete. */
780+
symbol_list const *r = self->rule;
781+
char const *lhs_type = r->content.sym->content->type_name;
782+
if (!lhs_type)
783+
return false;
784+
785+
/* The default action is installed for any rule with a non-empty
786+
RHS. But it feels less natural not to write the action in this
787+
case. Besides, the real point of -Wuseless-action is to help
788+
getting rid of useless chain rules by exhibiting more
789+
opportunities. And this is only for rules with a single RHS
790+
symbol (so two symbols with the LHS). */
791+
if (symbol_list_length (r) != 2)
792+
return false;
793+
794+
/* If the first rhs is a dummy, then we cannot simply remove the
795+
default action that is afterwards. Something fishy is going on,
796+
but maybe a different warning for this case?
797+
798+
foo: bar { $$ = 42; } { $$ = $1; } */
799+
symbol const *rhs = r->next->content.sym;
800+
if (symbol_is_dummy (rhs))
801+
return false;
802+
803+
char const *rhs_type = rhs->content->type_name;
804+
if (!UNIQSTR_EQ (lhs_type, rhs_type ? rhs_type : ""))
805+
return false;
806+
807+
return strspacecmp (self->code, "{ $$ = $1; }") == 0;
808+
}
809+
810+
746811
/*-------------------------.
747812
| Initialize the scanner. |
748813
`-------------------------*/
@@ -761,6 +826,15 @@ translate_action (code_props *self, int sc_context)
761826
initialized = true;
762827
}
763828

829+
/* Warn about explicit default actions. */
830+
if (sc_context == SC_RULE_ACTION
831+
&& warning_is_enabled (Wuseless_action)
832+
&& useless_default_action (self))
833+
{
834+
complain (&self->location, Wuseless_action, _("useless explicit action"));
835+
fixits_register (&self->location, "");
836+
}
837+
764838
loc->start = loc->end = self->location.start;
765839
yy_switch_to_buffer (yy_scan_string (self->code));
766840
char *res = code_lex (self, sc_context);

tests/actions.at

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,46 @@ AT_PARSER_CHECK([input], 0,
115115
AT_CLEANUP
116116

117117

118+
## ------------------------- ##
119+
## Useless default actions. ##
120+
## ------------------------- ##
121+
122+
AT_SETUP([Useless default actions])
123+
124+
AT_BISON_OPTION_PUSHDEFS
125+
AT_DATA_GRAMMAR([[input.y]],
126+
[[%union {
127+
int ival;
128+
int ival2;
129+
}
130+
%type <ival> expr term fact
131+
%type <ival2> "number"
132+
%%
133+
expr: expr '+' term { $$ = $1; } // No warning: too many symbols.
134+
expr: term { $$ = $1; }
135+
term: term '*' fact { $$ = $1; } | fact { $$ = $1 ; }
136+
// No warning: types differ.
137+
fact: "number" { $$ = $1; }
138+
// No warning: there is a midrule action.
139+
fact: <ival>{ $$ = 42; } { $$ = $1; }
140+
;
141+
%%
142+
]])
143+
AT_BISON_OPTION_POPDEFS
144+
145+
AT_BISON_CHECK([-Wuseless-action -fcaret input.y], [], [],
146+
[[input.y:17.12-23: warning: useless explicit action [-Wuseless-action]
147+
17 | expr: term { $$ = $1; }
148+
| ^~~~~~~~~~~~
149+
input.y:18.41-57: warning: useless explicit action [-Wuseless-action]
150+
18 | term: term '*' fact { $$ = $1; } | fact { $$ = $1 ; }
151+
| ^~~~~~~~~~~~~~~~~
152+
input.y: warning: fix-its can be applied. Rerun with option '--update'. [-Wother]
153+
]])
154+
AT_CLEANUP
155+
156+
157+
118158
## ----------------------- ##
119159
## Implicitly empty rule. ##
120160
## ----------------------- ##

0 commit comments

Comments
 (0)