warnings: add [warning push] and [warning pop]

Add [warning push] and [warning pop] directives.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin (Intel) 2019-01-11 13:13:03 -08:00
parent 38ddb19977
commit 1df7263ae9
8 changed files with 124 additions and 30 deletions

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
* the specific copyright holders.
*
@ -421,7 +421,14 @@ bool process_directives(char *directive)
break;
}
case D_WARNING: /* [WARNING {+|-|*}warn-name] */
case D_WARNING: /* [WARNING {push|pop|{+|-|*}warn-name}] */
value = nasm_skip_spaces(value);
if ((*value | 0x20) == 'p') {
if (!nasm_stricmp(value, "push"))
push_warnings();
else if (!nasm_stricmp(value, "pop"))
pop_warnings();
}
set_warning_status(value);
break;

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
* the specific copyright holders.
*
@ -85,7 +85,7 @@ void nasm_warn(errflags severity, const char *fmt, ...)
{
nasm_do_error(ERR_WARNING|severity);
}
fatal_func nasm_panic_from_macro(const char *file, int line)
{
nasm_panic("internal error at %s:%d\n", file, line);
@ -96,6 +96,72 @@ fatal_func nasm_assert_failed(const char *file, int line, const char *msg)
nasm_panic("assertion %s failed at %s:%d", msg, file, line);
}
/*
* Warning stack management. Note that there is an implicit "push"
* after the command line has been parsed, but this particular push
* cannot be popped.
*/
struct warning_stack {
struct warning_stack *next;
uint8_t state[sizeof warning_state];
};
static struct warning_stack *warning_stack, *warning_state_init;
/* Push the warning status onto the warning stack */
void push_warnings(void)
{
struct warning_stack *ws;
ws = nasm_malloc(sizeof *ws);
memcpy(ws->state, warning_state, sizeof warning_state);
ws->next = warning_stack;
warning_stack = ws;
}
/* Pop the warning status off the warning stack */
void pop_warnings(void)
{
struct warning_stack *ws = warning_stack;
memcpy(warning_state, ws->state, sizeof warning_state);
if (!ws->next) {
/*!
*!warn-stack-empty [on] warning stack empty
*! a [WARNING POP] directive was executed when
*! the warning stack is empty. This is treated
*! as a [WARNING *all] directive.
*/
nasm_warn(WARN_WARN_STACK_EMPTY, "warning stack empty");
} else {
warning_stack = ws->next;
nasm_free(ws);
}
}
/* Call after the command line is parsed, but before the first pass */
void init_warnings(void)
{
push_warnings();
warning_state_init = warning_stack;
}
/* Call after each pass */
void reset_warnings(void)
{
struct warning_stack *ws = warning_stack;
/* Unwind the warning stack. We do NOT delete the last entry! */
while (ws->next) {
struct warning_stack *wst = ws;
ws = ws->next;
nasm_free(wst);
}
warning_stack = ws;
memcpy(warning_state, ws->state, sizeof warning_state);
}
/*
* This is called when processing a -w or -W option, or a warning directive.
* Returns on if if the action was successful.
@ -120,6 +186,7 @@ bool set_warning_status(const char *value)
int i;
value = nasm_skip_spaces(value);
switch (*value) {
case '-':
action = WID_OFF;
@ -185,7 +252,8 @@ bool set_warning_status(const char *value)
break;
case WID_RESET:
warning_state[i] &= ~mask;
warning_state[i] |= warning_state_init[i] & mask;
warning_state[i] |=
warning_state_init->state[i] & mask;
break;
}
}
@ -199,6 +267,6 @@ bool set_warning_status(const char *value)
*/
nasm_warn(WARN_UNKNOWN_WARNING, "unknown warning name: %s", name);
}
return ok;
}

View File

@ -511,7 +511,7 @@ int main(int argc, char **argv)
}
/* Save away the default state of warnings */
memcpy(warning_state_init, warning_state, sizeof warning_state_init);
init_warnings();
/* Dependency filename if we are also doing other things */
if (!depend_file && (operating_mode & ~OP_DEPEND)) {
@ -550,6 +550,7 @@ int main(int argc, char **argv)
while ((line = preproc->getline()))
nasm_free(line);
preproc->cleanup_pass();
reset_warnings();
} else if (operating_mode & OP_PREPROCESS) {
char *line;
const char *file_name = NULL;
@ -568,9 +569,6 @@ int main(int argc, char **argv)
_pass_type = PASS_FIRST; /* We emulate this assembly pass */
preproc->reset(inname, PP_PREPROC, depend_list);
/* Revert all warnings to the default state */
memcpy(warning_state, warning_state_init, sizeof warning_state);
while ((line = preproc->getline())) {
/*
* We generate %line directives if needed for later programs
@ -592,6 +590,7 @@ int main(int argc, char **argv)
nasm_free(line);
}
preproc->cleanup_pass();
reset_warnings();
if (ofile)
fclose(ofile);
if (ofile && terminate_after_phase && !keep_all)
@ -1334,8 +1333,7 @@ static void parse_cmdline(int argc, char **argv, int pass)
* Initialize all the warnings to their default state, including
* warning index 0 used for "always on".
*/
memcpy(warning_state, warning_default, sizeof warning_state);
memcpy(warning_state_init, warning_default, sizeof warning_state_init);
memcpy(warning_state, warning_default, sizeof warning_state);
/*
* First, process the NASMENV environment variable.
@ -1546,9 +1544,6 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
switch_segment(ofmt->section(NULL, &globalbits));
preproc->reset(fname, PP_NORMAL, pass_final() ? depend_list : NULL);
/* Revert all warnings to the default state */
memcpy(warning_state, warning_state_init, sizeof warning_state);
globallineno = 0;
while ((line = preproc->getline())) {
@ -1575,10 +1570,6 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
preproc->cleanup_pass();
/* Don't output further messages if we are dead anyway */
if (terminate_after_phase)
break;
if (global_offset_changed) {
switch (pass_type()) {
case PASS_OPT:
@ -1596,11 +1587,13 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
if (stall_count > nasm_limit[LIMIT_STALLED] ||
pass_count() >= nasm_limit[LIMIT_PASSES]) {
/* No convergence, almost certainly dead */
nasm_nonfatal("unable to find valid values for all labels "
"after %"PRId64" passes; "
"stalled for %"PRId64", giving up.",
pass_count(), stall_count);
nasm_note("Possible causes: recursive EQUs, macro abuse.");
nasm_nonfatalf(ERR_UNDEAD,
"unable to find valid values for all labels "
"after %"PRId64" passes; "
"stalled for %"PRId64", giving up.",
pass_count(), stall_count);
nasm_notef(ERR_UNDEAD,
"Possible causes: recursive EQUs, macro abuse.");
}
break;
@ -1611,12 +1604,14 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
*! the second-to-last assembly pass. This is not
*! inherently fatal, but may be a source of bugs.
*/
nasm_warn(WARN_PHASE, "phase error during stabilization "
nasm_warn(WARN_PHASE|ERR_UNDEAD,
"phase error during stabilization "
"pass, hoping for the best");
break;
case PASS_FINAL:
nasm_nonfatal("phase error during code generation pass");
nasm_nonfatalf(ERR_UNDEAD,
"phase error during code generation pass");
break;
default:
@ -1624,6 +1619,8 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
break;
}
}
reset_warnings();
}
if (opt_verbose_info && pass_final()) {

View File

@ -132,8 +132,6 @@ if ($what eq 'c') {
print $out "\n};\n\n";
printf $out "uint8_t warning_state[%d];\t/* Current state */\n",
$#warn_noall + 2;
printf $out "uint8_t warning_state_init[%d];\t/* Command-line state, for reset */\n",
$#warn_noall + 2;
} elsif ($what eq 'h') {
my $filename = basename($outfile);
my $guard = $filename;
@ -174,8 +172,6 @@ if ($what eq 'c') {
$#warn_noall + 2;
printf $out "extern uint8_t warning_state[%d];\n",
$#warn_noall + 2;
printf $out "extern uint8_t warning_state_init[%d];\n",
$#warn_noall + 2;
print $out "\n#endif /* $guard */\n";
} elsif ($what eq 'doc') {
my %whatdef = ( 'on' => 'Enabled',

View File

@ -7,6 +7,12 @@
The NASM 2 series supports x86-64, and is the production version of NASM
since 2007.
\S{cl-2.15} Version 2.15
\b The state of warnings can now be saved and restored via the
\c{[WARNING PUSH]} and \c{[WARNING POP]} directives. See
\k{asmdir-warning}.
\S{cl-2.14.03} Version 2.14.03
\b Suppress nuisance "\c{label changed during code generation}" messages

View File

@ -4776,6 +4776,10 @@ more details about warning classes.
the original value, either the default value or as specified on the
command line.
\b \c{[warning push]} saves the current warning state on a stack.
\b \c{[warning pop]} restores the current warning state from the stack.
The \c{[WARNING]} directive also accepts the \c{all}, \c{error} and
\c{error=}\e{warning-class} specifiers.

View File

@ -122,6 +122,12 @@ static inline vefunc nasm_set_verror(vefunc ve)
/* Process a warning option or directive */
bool set_warning_status(const char *value);
/* Warning stack management */
void push_warnings(void);
void pop_warnings(void);
void init_warnings(void);
void reset_warnings(void);
/* Should be included from within error.h only */
#include "warnings.h"

10
test/warnstack.asm Normal file
View File

@ -0,0 +1,10 @@
%warning "Good warning"
[warning push]
[warning -user]
%warning "Bad warning"
[warning pop]
%warning "Good warning"
[warning -user]
%warning "Bad warning"
[warning pop] ; should warn but reset all
%warning "Good warning"