Add group aliases for all prefixed warnings.

For example, -w+float will now enable all warnings with names staring
with float-*.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin 2019-06-06 20:53:17 -07:00
parent 186f9a0514
commit fdeb3b0d01
12 changed files with 145 additions and 64 deletions

View File

@ -172,18 +172,18 @@ void reset_warnings(void)
*! specifies any warning not included in any specific warning class. *! specifies any warning not included in any specific warning class.
* *
*!all [all] all possible warnings *!all [all] all possible warnings
*! is an alias for \e{all} suppressible warning classes. *! is an group alias for \e{all} warning classes. Thus, \c{-w+all}
*! Thus, \c{-w+all} enables all available warnings, and \c{-w-all} *! enables all available warnings, and \c{-w-all} disables warnings
*! disables warnings entirely (since NASM 2.13). *! entirely (since NASM 2.13).
*/ */
bool set_warning_status(const char *value) bool set_warning_status(const char *value)
{ {
enum warn_action { WID_OFF, WID_ON, WID_RESET }; enum warn_action { WID_OFF, WID_ON, WID_RESET };
enum warn_action action; enum warn_action action;
const char *name; const struct warning_alias *wa;
size_t vlen;
bool ok = false; bool ok = false;
uint8_t mask; uint8_t mask;
int i;
value = nasm_skip_spaces(value); value = nasm_skip_spaces(value);
@ -235,37 +235,48 @@ bool set_warning_status(const char *value)
} }
} }
name = value ? value : "<none>";
if (value && !nasm_stricmp(value, "all")) if (value && !nasm_stricmp(value, "all"))
value = NULL; value = NULL;
/* This is inefficient, but it shouldn't matter... */ vlen = value ? strlen(value) : 0;
for (i = 1; i < WARN_IDX_ALL; i++) {
if (!value || !nasm_stricmp(value, warning_name[i])) {
ok = true; /* At least one action taken */
switch (action) {
case WID_OFF:
warning_state[i] &= ~mask;
break;
case WID_ON:
warning_state[i] |= mask;
break;
case WID_RESET:
warning_state[i] &= ~mask;
warning_state[i] |=
warning_state_init->state[i] & mask;
break;
}
}
}
if (!ok) { /* This is inefficient, but it shouldn't matter... */
/*! for (wa = warning_alias; wa < &warning_alias[NUM_WARNING_ALIAS]; wa++) {
*!unknown-warning [off] unknown warning in -W/-w or warning directive enum warn_index i = wa->warning;
*! warns about a \c{-w} or \c{-W} option or a \c{[WARNING]} directive
*! that contains an unknown warning name or is otherwise not possible to process. if (value) {
*/ char sep;
nasm_warn(WARN_UNKNOWN_WARNING, "unknown warning name: %s", name);
if (nasm_strnicmp(value, wa->name, vlen))
continue; /* Not a prefix */
sep = wa->name[vlen];
if (sep != '\0' && sep != '-')
continue; /* Not a valid prefix */
}
ok = true; /* At least one action taken */
switch (action) {
case WID_OFF:
warning_state[i] &= ~mask;
break;
case WID_ON:
warning_state[i] |= mask;
break;
case WID_RESET:
warning_state[i] &= ~mask;
warning_state[i] |= warning_state_init->state[i] & mask;
break;
}
}
if (!ok && value) {
/*!
*!unknown-warning [off] unknown warning in -W/-w or warning directive
*! warns about a \c{-w} or \c{-W} option or a \c{[WARNING]} directive
*! that contains an unknown warning name or is otherwise not possible to process.
*/
nasm_warn(WARN_UNKNOWN_WARNING, "unknown warning name: %s", value);
} }
return ok; return ok;

View File

@ -201,7 +201,7 @@ nasm_set_limit(const char *limit, const char *valstr)
if (not_started()) if (not_started())
errlevel = ERR_WARNING|WARN_OTHER|ERR_USAGE; errlevel = ERR_WARNING|WARN_OTHER|ERR_USAGE;
else else
errlevel = ERR_WARNING|WARN_UNKNOWN_PRAGMA; errlevel = ERR_WARNING|WARN_PRAGMA_UNKNOWN;
nasm_error(errlevel, "unknown limit: `%s'", limit); nasm_error(errlevel, "unknown limit: `%s'", limit);
return DIRR_ERROR; return DIRR_ERROR;
} }
@ -214,7 +214,7 @@ nasm_set_limit(const char *limit, const char *valstr)
if (not_started()) if (not_started())
errlevel = ERR_WARNING|WARN_OTHER|ERR_USAGE; errlevel = ERR_WARNING|WARN_OTHER|ERR_USAGE;
else else
errlevel = ERR_WARNING|WARN_BAD_PRAGMA; errlevel = ERR_WARNING|WARN_PRAGMA_BAD;
nasm_error(errlevel, "invalid limit value: `%s'", limit); nasm_error(errlevel, "invalid limit value: `%s'", limit);
return DIRR_ERROR; return DIRR_ERROR;
} }

View File

@ -460,12 +460,13 @@ restart_parse:
i = stdscan(NULL, &tokval); i = stdscan(NULL, &tokval);
} else if (i == 0) { } else if (i == 0) {
/*! /*!
*!orphan-labels [on] labels alone on lines without trailing `:' *!label-orphan [on] labels alone on lines without trailing `:'
*!=orphan-labels
*! warns about source lines which contain no instruction but define *! warns about source lines which contain no instruction but define
*! a label without a trailing colon. This is most likely indicative *! a label without a trailing colon. This is most likely indicative
*! of a typo, but is technically correct NASM syntax (see \k{syntax}.) *! of a typo, but is technically correct NASM syntax (see \k{syntax}.)
*/ */
nasm_warn(WARN_ORPHAN_LABELS , nasm_warn(WARN_LABEL_ORPHAN ,
"label alone on a line without a colon might be in error"); "label alone on a line without a colon might be in error");
} }
if (i != TOKEN_INSN || tokval.t_integer != I_EQU) { if (i != TOKEN_INSN || tokval.t_integer != I_EQU) {

View File

@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- * /* ----------------------------------------------------------------------- *
* *
* Copyright 1996-2018 The NASM Authors - All Rights Reserved * Copyright 1996-2019 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for * See the file AUTHORS included with the NASM distribution for
* the specific copyright holders. * the specific copyright holders.
* *
@ -144,20 +144,22 @@ found_it:
switch (pragma->opcode) { switch (pragma->opcode) {
case D_none: case D_none:
/*! /*!
*!bad-pragma [off] empty or malformed %pragma *!pragma-bad [off] empty or malformed %pragma
*!=bad-pragma
*! warns about a malformed or otherwise unparsable *! warns about a malformed or otherwise unparsable
*! \c{%pragma} directive. *! \c{%pragma} directive.
*/ */
nasm_error(ERR_WARNING|ERR_PASS2|WARN_BAD_PRAGMA, nasm_error(ERR_WARNING|ERR_PASS2|WARN_PRAGMA_BAD,
"empty %%pragma %s", pragma->facility_name); "empty %%pragma %s", pragma->facility_name);
break; break;
default: default:
/*! /*!
*!unknown-pragma [off] unknown %pragma facility or directive *!pragma-unknown [off] unknown %pragma facility or directive
*!=unknown-pragma
*! warns about an unknown \c{%pragma} directive. *! warns about an unknown \c{%pragma} directive.
*! This is not yet implemented for most cases. *! This is not yet implemented for most cases.
*/ */
nasm_error(ERR_WARNING|ERR_PASS2|WARN_UNKNOWN_PRAGMA, nasm_error(ERR_WARNING|ERR_PASS2|WARN_PRAGMA_UNKNOWN,
"unknown %%pragma %s %s", "unknown %%pragma %s %s",
pragma->facility_name, pragma->opname); pragma->facility_name, pragma->opname);
break; break;
@ -185,7 +187,8 @@ found_it:
/* This warning message is intended for future use */ /* This warning message is intended for future use */
/*! /*!
*!not-my-pragma [off] %pragma not applicable to this compilation *!pragma-na [off] %pragma not applicable to this compilation
*!=not-my-pragma
*! warns about a \c{%pragma} directive which is not applicable to *! warns about a \c{%pragma} directive which is not applicable to
*! this particular assembly session. This is not yet implemented. *! this particular assembly session. This is not yet implemented.
*/ */
@ -199,7 +202,7 @@ void process_pragma(char *str)
pragma.facility_name = nasm_get_word(str, &p); pragma.facility_name = nasm_get_word(str, &p);
if (!pragma.facility_name) { if (!pragma.facility_name) {
nasm_error(ERR_WARNING|ERR_PASS2|WARN_BAD_PRAGMA, nasm_error(ERR_WARNING|ERR_PASS2|WARN_PRAGMA_BAD,
"empty pragma directive"); "empty pragma directive");
return; /* Empty pragma */ return; /* Empty pragma */
} }

View File

@ -5,6 +5,8 @@ use File::Find;
use File::Basename; use File::Basename;
my @warnings = (); my @warnings = ();
my %aliases = ();
my %prefixes = ();
my $err = 0; my $err = 0;
my $nwarn = 0; my $nwarn = 0;
@ -15,6 +17,22 @@ sub quote_for_c($) {
return $s; return $s;
} }
sub add_alias($$) {
my($a, $this) = @_;
my @comp = split(/-/, $a);
$aliases{$a} = $this;
# All names are prefixes in their own right, although we only
# list the ones that are either prefixes of "proper names" or
# the complete alias name.
for (my $i = ($a eq $this->{name}) ? 0 : $#comp; $i <= $#comp; $i++) {
my $prefix = join('-', @comp[0..$i]);
$prefixes{$prefix} = [] unless defined($prefixes{$prefix});
push(@{$prefixes{$prefix}}, $a);
}
}
sub find_warnings { sub find_warnings {
my $infile = $_; my $infile = $_;
@ -51,9 +69,9 @@ sub find_warnings {
my $str = $2; my $str = $2;
next if ($str eq ''); next if ($str eq '');
if (!defined($this) || ($ws eq '' && $str ne '')) { if (!defined($this) || ($ws eq '' && $str ne '')) {
if ($str =~ /^([\w-]+)\s+\[(\w+)\]\s(.+)$/) { if ($str =~ /^([\w-]+)\s+\[(\w+)\]\s(.*\S)\s*$/) {
my $name = $1; my $name = $1;
my $def = $2; my $def = $2;
my $help = $3; my $help = $3;
@ -62,10 +80,17 @@ sub find_warnings {
$cname =~ s/[^A-Z0-9_]+/_/g; $cname =~ s/[^A-Z0-9_]+/_/g;
$this = {name => $name, cname => $cname, $this = {name => $name, cname => $cname,
def => $def, help => $help, doc => [], def => $def, help => $help,
file => $infile, line => $nline}; doc => [], file => $infile, line => $nline};
push(@warnings, $this); push(@warnings, $this);
# Every warning name is also a valid warning alias
add_alias($name, $this);
$nwarn++; $nwarn++;
} elsif (defined($this) && $str =~ /^\=([\w-,]+)\s*$/) {
# Alias names for warnings
for my $a (split(/,+/, $1)) {
add_alias($a, $this);
}
} else { } else {
print STDERR "$infile:$nline: malformed warning definition\n"; print STDERR "$infile:$nline: malformed warning definition\n";
print STDERR " $l\n"; print STDERR " $l\n";
@ -115,6 +140,16 @@ if ($what eq 'c') {
print $out ",\n\t\"", $warn->{name}, "\""; print $out ",\n\t\"", $warn->{name}, "\"";
} }
print $out "\n};\n\n"; print $out "\n};\n\n";
printf $out "const struct warning_alias warning_alias[NUM_WARNING_ALIAS] = {",
scalar(%aliases);
my $sep = '';
foreach my $alias (sort { $a cmp $b } keys(%aliases)) {
printf $out "%s\n\t{ %-27s WARN_IDX_%s }",
$sep, "\"$alias\",", $aliases{$alias}->{cname};
$sep = ',';
}
print $out "\n};\n\n";
printf $out "const char * const warning_help[%d] = {\n", printf $out "const char * const warning_help[%d] = {\n",
$#warnings + 2; $#warnings + 2;
print $out "\tNULL"; print $out "\tNULL";
@ -164,10 +199,17 @@ if ($what eq 'c') {
} }
print $out "\n};\n\n"; print $out "\n};\n\n";
print $out "struct warning_alias {\n";
print $out "\tconst char *name;\n";
print $out "\tenum warn_index warning;\n";
print $out "};\n\n";
printf $out "#define NUM_WARNING_ALIAS %d\n", scalar(%aliases);
printf $out "extern const char * const warning_name[%d];\n", printf $out "extern const char * const warning_name[%d];\n",
$#warnings + 2; $#warnings + 2;
printf $out "extern const char * const warning_help[%d];\n", printf $out "extern const char * const warning_help[%d];\n",
$#warnings + 2; $#warnings + 2;
print $out "extern const struct warning_alias warning_alias[NUM_WARNING_ALIAS];\n";
printf $out "extern const uint8_t warning_default[%d];\n", printf $out "extern const uint8_t warning_default[%d];\n",
$#warn_noall + 2; $#warn_noall + 2;
printf $out "extern uint8_t warning_state[%d];\n", printf $out "extern uint8_t warning_state[%d];\n",
@ -177,20 +219,44 @@ if ($what eq 'c') {
my %whatdef = ( 'on' => 'Enabled', my %whatdef = ( 'on' => 'Enabled',
'off' => 'Disabled', 'off' => 'Disabled',
'err' => 'Enabled and promoted to error' ); 'err' => 'Enabled and promoted to error' );
foreach my $warn (@warnings) {
my @doc = @{$warn->{doc}}; foreach my $pfx (sort { $a cmp $b } keys(%prefixes)) {
shift @doc while ($doc[0] =~ /^\s*$/); my $warn = $aliases{$pfx};
pop @doc while ($doc[$#doc] =~ /^\s*$/); my @doc;
print $out "\\b \\i\\c{", $warn->{name}, "} ", @doc; if (!defined($warn)) {
my @plist = sort { $a cmp $b } @{$prefixes{$pfx}};
next if ( $#plist < 1 );
my $docdef = $whatdef{$warn->{def}}; @doc = ("is a group alias for all warning classes prefixed by ".
if (defined($docdef)) { "\\c{".$pfx."-}; currently\n");
print $out $docdef, " by default.\n"; for (my $i = 0; $i <= $#plist; $i++) {
if ($i > 0) {
if ($i < $#plist) {
push(@doc, ", ");
} else {
push(@doc, ($i == 1) ? " and " : ", and ");
}
}
push(@doc, '\c{'.$plist[$i].'}');
}
push(@doc, ".\n");
} elsif ($pfx ne $warn->{name}) {
@doc = ("is a backwards compatibility alias for \\c{",
$warn->{name}, "}.\n");
} else {
my $docdef = $whatdef{$warn->{def}};
@doc = @{$warn->{doc}};
shift @doc while ($doc[0] =~ /^\s*$/);
pop @doc while ($doc[$#doc] =~ /^\s*$/);
if (defined($docdef)) {
push(@doc, "$docdef by default.\n");
}
} }
print $out "\n"; print $out "\\b \\i\\c{", $pfx, "} ", @doc, "\n";
} }
} }
close($out); close($out);

View File

@ -126,11 +126,11 @@ OPTIONS
*-W[no-]foo':: *-W[no-]foo'::
Causes *nasm* to enable or disable certain classes of warning messages, Causes *nasm* to enable or disable certain classes of warning messages,
in gcc-like style, for example *-Worphan-labels* or *-Wno-orphan-labels*. in gcc-like style, for example *-Wlabel-orphan* or *-Wno-orphan-labels*.
*-w*'[+-]foo':: *-w*'[+-]foo'::
Causes *nasm* to enable or disable certain classes of warning messages, Causes *nasm* to enable or disable certain classes of warning messages,
for example *-w+orphan-labels* or *-w-macro-params*. for example *-w+label-orphan* or *-w-macro-params*.
*-X* 'format':: *-X* 'format'::
Specifies error reporting format (gnu or vc). Specifies error reporting format (gnu or vc).

View File

@ -371,7 +371,7 @@ dbg_pragma(const struct pragma *pragma)
errno = 0; errno = 0;
arg = strtoul(pragma->tail, &ep, 0); arg = strtoul(pragma->tail, &ep, 0);
if (errno || *nasm_skip_spaces(ep)) { if (errno || *nasm_skip_spaces(ep)) {
nasm_error(ERR_WARNING | WARN_BAD_PRAGMA | ERR_PASS2, nasm_error(ERR_WARNING | WARN_PRAGMA_BAD | ERR_PASS2,
"invalid %%pragma dbg maxdump argument"); "invalid %%pragma dbg maxdump argument");
return DIRR_ERROR; return DIRR_ERROR;
} else { } else {

View File

@ -17,7 +17,7 @@ _start:
; either of the following lines cause: Error in `nasm': double free or corruption ; Aborted (core dumped) ; either of the following lines cause: Error in `nasm': double free or corruption ; Aborted (core dumped)
foo foo
; warning: label alone on a line without a colon might be in error [-w+orphan-labels] ; warning: label alone on a line without a colon might be in error [-w+label-orphan]
mov r8, r9, r10 mov r8, r9, r10
; error: invalid combination of opcode and operands ; error: invalid combination of opcode and operands
add r8d, byte 80h add r8d, byte 80h

View File

@ -1 +1 @@
./travis/test/aoutso.asm:79: warning: label alone on a line without a colon might be in error [-w+orphan-labels] ./travis/test/aoutso.asm:79: warning: label alone on a line without a colon might be in error [-w+label-orphan]

View File

@ -1 +1 @@
./travis/test/elfso.asm:83: warning: label alone on a line without a colon might be in error [-w+orphan-labels] ./travis/test/elfso.asm:83: warning: label alone on a line without a colon might be in error [-w+label-orphan]

View File

@ -1 +1 @@
./travis/test/elfso.asm:83: warning: label alone on a line without a colon might be in error [-w+orphan-labels] ./travis/test/elfso.asm:83: warning: label alone on a line without a colon might be in error [-w+label-orphan]

View File

@ -1 +1 @@
./travis/test/tmap.asm:938: warning: label alone on a line without a colon might be in error [-w+orphan-labels] ./travis/test/tmap.asm:938: warning: label alone on a line without a colon might be in error [-w+label-orphan]