diff --git a/NEWS b/NEWS index 742ea743..4eb22cb7 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,44 @@ GNU Bison NEWS ** New Features +*** New diagnostic: -Wdangling-alias + + String literals, which allow for better error messages, are (too) + liberally accepted by Bison, which might result in silent errors. For + instance + + %type cond "condition" + + does not define "condition" as a string alias to 'cond' (nonterminal + symbols do not have string aliases). It is rather equivalent to + + %nterm cond + %token "condition" + + i.e., it gives the type 'exVal' to the "condition" token, which was + clearly not the intention. + + Also, because string aliases need not be defined, typos such as "baz" + instead of "bar" will be not reported. + + The option -Wdangling-alias catches these situations. On + + %token BAR "bar" + %type foo "foo" + %% + foo: "baz" {} + + bison -Wdangling-alias reports + + warning: string literal not attached to a symbol + | %type foo "foo" + | ^~~~~ + warning: string literal not attached to a symbol + | foo: "baz" {} + | ^~~~~ + + The -Wall option does not (yet?) include -Wdangling-alias. + *** Better POSIX Yacc compatibility diagnostics POSIX Yacc restricts %type to nonterminals. This is now diagnosed by diff --git a/doc/bison.texi b/doc/bison.texi index d9495ffe..96dbd2a5 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -3551,8 +3551,9 @@ They are still considered distinct rules even when joined in this way. @findex %empty A rule is said to be @dfn{empty} if its right-hand side (@var{components}) -is empty. It means that @var{result} can match the empty string. For -example, here is how to define an optional semicolon: +is empty. It means that @var{result} in the previous example can match the +empty string. As another example, here is how to define an optional +semicolon: @example semicolon.opt: | ";"; @@ -10531,6 +10532,52 @@ unexpected number of conflicts is an error, and an expected number of conflicts is not reported, so @option{-W} and @option{--warning} then have no effect on the conflict report. +@item dangling-alias +Report string literals that are not bound to a token symbol. + +String literals, which allow for better error messages, are (too) liberally +accepted by Bison, which might result in silent errors. For instance + +@example +%type cond "condition" +@end example + +@noindent +does not define ``condition'' as a string alias to @code{cond}---nonterminal +symbols do not have string aliases. It is rather equivalent to + +@example +%nterm cond +%token "condition" +@end example + +@noindent +i.e., it gives the @samp{"condition"} token the type @code{exVal}. + +Also, because string aliases do not need to be defined, typos such as +@samp{"baz"} instead of @samp{"bar"} will be not reported. + +The option @option{-Wdangling-alias} catches these situations. On + +@example +%token BAR "bar" +%type foo "foo" +%% +foo: "baz" @{@} +@end example + +@noindent +@command{bison -Wdangling-alias} reports + +@example +@dwarning{warning}: string literal not attached to a symbol + | %type foo @dwarning{"foo"} + | @dwarning{^~~~~} +@dwarning{warning}: string literal not attached to a symbol + | foo: @dwarning{"baz"} @{@} + | @dwarning{^~~~~} +@end example + @item deprecated Deprecated constructs whose support will be removed in future versions of Bison. @@ -10632,7 +10679,7 @@ releases of Bison may move warnings from this category to new, more specific categories. @item all -All the warnings except @code{yacc}. +All the warnings except @code{dangling-alias} and @code{yacc}. @item none Turn off all the warnings. diff --git a/src/complain.c b/src/complain.c index 87563d59..d945d583 100644 --- a/src/complain.c +++ b/src/complain.c @@ -113,13 +113,14 @@ static const argmatch_warning_doc argmatch_warning_docs[] = { { "conflicts-sr", N_("S/R conflicts (enabled by default)") }, { "conflicts-rr", N_("R/R conflicts (enabled by default)") }, + { "dangling-alias", N_("string aliases not attached to a symbol") }, { "deprecated", N_("obsolete constructs") }, { "empty-rule", N_("empty rules without %empty") }, { "midrule-values", N_("unset or unused midrule values") }, { "precedence", N_("useless precedence and associativity") }, { "yacc", N_("incompatibilities with POSIX Yacc") }, { "other", N_("all other warnings (enabled by default)") }, - { "all", N_("all the warnings except 'yacc'") }, + { "all", N_("all the warnings except 'dangling-alias' and 'yacc'") }, { "no-CATEGORY", N_("turn off warnings in CATEGORY") }, { "none", N_("turn off all the warnings") }, { "error[=CATEGORY]", N_("treat warnings as errors") }, @@ -128,17 +129,18 @@ static const argmatch_warning_doc argmatch_warning_docs[] = static const argmatch_warning_arg argmatch_warning_args[] = { - { "none", Wnone }, - { "midrule-values", Wmidrule_values }, - { "yacc", Wyacc }, - { "conflicts-sr", Wconflicts_sr }, + { "all", Wall }, { "conflicts-rr", Wconflicts_rr }, + { "conflicts-sr", Wconflicts_sr }, + { "dangling-alias", Wdangling_alias }, { "deprecated", Wdeprecated }, { "empty-rule", Wempty_rule }, - { "precedence", Wprecedence }, - { "other", Wother }, - { "all", Wall }, { "everything", Weverything }, + { "midrule-values", Wmidrule_values }, + { "none", Wnone }, + { "other", Wother }, + { "precedence", Wprecedence }, + { "yacc", Wyacc }, { NULL, Wnone } }; diff --git a/src/complain.h b/src/complain.h index 4b73d08d..5d112c23 100644 --- a/src/complain.h +++ b/src/complain.h @@ -47,6 +47,7 @@ typedef enum { warning_conflicts_rr, warning_conflicts_sr, + warning_dangling_alias, warning_deprecated, warning_empty_rule, warning_midrule_values, @@ -104,6 +105,7 @@ typedef enum Wconflicts_rr = 1 << warning_conflicts_rr, Wconflicts_sr = 1 << warning_conflicts_sr, + Wdangling_alias = 1 << warning_dangling_alias, Wdeprecated = 1 << warning_deprecated, Wempty_rule = 1 << warning_empty_rule, Wmidrule_values = 1 << warning_midrule_values, @@ -118,7 +120,7 @@ typedef enum /**< All above warnings. */ Weverything = ~complaint & ~fatal & ~silent, - Wall = Weverything & ~Wyacc + Wall = Weverything & ~Wdangling_alias & ~Wyacc } warnings; /** Whether the warnings of \a flags are all unset. diff --git a/src/symtab.c b/src/symtab.c index 73111b51..589da0ae 100644 --- a/src/symtab.c +++ b/src/symtab.c @@ -26,12 +26,12 @@ #include #include #include +#include #include "complain.h" #include "getargs.h" #include "gram.h" #include "intprops.h" -#include "quote.h" static struct hash_table *symbol_table = NULL; static struct hash_table *semantic_type_table = NULL; @@ -610,6 +610,13 @@ symbol_check_defined (symbol *sym) s->number = nvars++; } + if (s->class == token_sym + && sym->tag[0] == '"' + && !sym->is_alias) + complain (&sym->location, Wdangling_alias, + _("string literal %s not attached to a symbol"), + sym->tag); + for (int i = 0; i < 2; ++i) symbol_code_props_get (sym, i)->is_used = true; diff --git a/tests/input.at b/tests/input.at index 00e3a508..96e20a71 100644 --- a/tests/input.at +++ b/tests/input.at @@ -298,6 +298,31 @@ input.y:8.14: error: syntax error, unexpected integer AT_CLEANUP +## ------------------ ## +## Dangling aliases. ## +## ------------------ ## + +AT_SETUP([Dangling aliases]) + +AT_DATA([input.y], +[[%token FOO "foo" +%type "bar" +%% +expr: "foo" "bar" "baz" +]]) + +AT_BISON_CHECK([-fcaret -Wdangling input.y], [0], [], +[[input.y:2.13-17: warning: string literal "bar" not attached to a symbol [-Wdangling-alias] + 2 | %type "bar" + | ^~~~~ +input.y:4.19-23: warning: string literal "baz" not attached to a symbol [-Wdangling-alias] + 4 | expr: "foo" "bar" "baz" + | ^~~~~ +]]) + +AT_CLEANUP + + ## --------------------- ## ## Symbol declarations. ## ## --------------------- ##