0
0
mirror of https://github.com/netwide-assembler/nasm.git synced 2025-09-22 10:43:39 -04:00

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 * See the file AUTHORS included with the NASM distribution for
* the specific copyright holders. * the specific copyright holders.
* *
@@ -421,7 +421,14 @@ bool process_directives(char *directive)
break; 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); set_warning_status(value);
break; 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 * See the file AUTHORS included with the NASM distribution for
* the specific copyright holders. * the specific copyright holders.
* *
@@ -85,7 +85,7 @@ void nasm_warn(errflags severity, const char *fmt, ...)
{ {
nasm_do_error(ERR_WARNING|severity); nasm_do_error(ERR_WARNING|severity);
} }
fatal_func nasm_panic_from_macro(const char *file, int line) fatal_func nasm_panic_from_macro(const char *file, int line)
{ {
nasm_panic("internal error at %s:%d\n", file, 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); 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. * This is called when processing a -w or -W option, or a warning directive.
* Returns on if if the action was successful. * Returns on if if the action was successful.
@@ -120,6 +186,7 @@ bool set_warning_status(const char *value)
int i; int i;
value = nasm_skip_spaces(value); value = nasm_skip_spaces(value);
switch (*value) { switch (*value) {
case '-': case '-':
action = WID_OFF; action = WID_OFF;
@@ -185,7 +252,8 @@ bool set_warning_status(const char *value)
break; break;
case WID_RESET: case WID_RESET:
warning_state[i] &= ~mask; warning_state[i] &= ~mask;
warning_state[i] |= warning_state_init[i] & mask; warning_state[i] |=
warning_state_init->state[i] & mask;
break; break;
} }
} }
@@ -199,6 +267,6 @@ bool set_warning_status(const char *value)
*/ */
nasm_warn(WARN_UNKNOWN_WARNING, "unknown warning name: %s", name); nasm_warn(WARN_UNKNOWN_WARNING, "unknown warning name: %s", name);
} }
return ok; return ok;
} }

View File

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

View File

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

View File

@@ -7,6 +7,12 @@
The NASM 2 series supports x86-64, and is the production version of NASM The NASM 2 series supports x86-64, and is the production version of NASM
since 2007. 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 \S{cl-2.14.03} Version 2.14.03
\b Suppress nuisance "\c{label changed during code generation}" messages \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 the original value, either the default value or as specified on the
command line. 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 The \c{[WARNING]} directive also accepts the \c{all}, \c{error} and
\c{error=}\e{warning-class} specifiers. \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 */ /* Process a warning option or directive */
bool set_warning_status(const char *value); 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 */ /* Should be included from within error.h only */
#include "warnings.h" #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"