mirror of
https://github.com/netwide-assembler/nasm.git
synced 2024-11-21 03:14:19 +08: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:
parent
38ddb19977
commit
1df7263ae9
@ -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;
|
||||
|
||||
|
76
asm/error.c
76
asm/error.c
@ -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;
|
||||
}
|
||||
|
37
asm/nasm.c
37
asm/nasm.c
@ -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()) {
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
10
test/warnstack.asm
Normal 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"
|
Loading…
Reference in New Issue
Block a user