From 1df7263ae937ac11abb2c6938b8891745af91ce6 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin (Intel)" Date: Fri, 11 Jan 2019 13:13:03 -0800 Subject: [PATCH] warnings: add [warning push] and [warning pop] Add [warning push] and [warning pop] directives. Signed-off-by: H. Peter Anvin (Intel) --- asm/directiv.c | 11 ++++++-- asm/error.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++--- asm/nasm.c | 37 ++++++++++++-------------- asm/warnings.pl | 4 --- doc/changes.src | 6 +++++ doc/nasmdoc.src | 4 +++ include/error.h | 6 +++++ test/warnstack.asm | 10 +++++++ 8 files changed, 124 insertions(+), 30 deletions(-) create mode 100644 test/warnstack.asm diff --git a/asm/directiv.c b/asm/directiv.c index 943e532f..cd13938d 100644 --- a/asm/directiv.c +++ b/asm/directiv.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. * @@ -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; diff --git a/asm/error.c b/asm/error.c index ef3fd988..4e86a0d7 100644 --- a/asm/error.c +++ b/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; } diff --git a/asm/nasm.c b/asm/nasm.c index 6a0a8b00..283f45d3 100644 --- a/asm/nasm.c +++ b/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()) { diff --git a/asm/warnings.pl b/asm/warnings.pl index cb336ada..0c2ed516 100755 --- a/asm/warnings.pl +++ b/asm/warnings.pl @@ -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', diff --git a/doc/changes.src b/doc/changes.src index a4df0473..ad539676 100644 --- a/doc/changes.src +++ b/doc/changes.src @@ -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 diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src index 5ce113a2..a8559d46 100644 --- a/doc/nasmdoc.src +++ b/doc/nasmdoc.src @@ -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. diff --git a/include/error.h b/include/error.h index 03380764..9091fe81 100644 --- a/include/error.h +++ b/include/error.h @@ -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" diff --git a/test/warnstack.asm b/test/warnstack.asm new file mode 100644 index 00000000..6e762904 --- /dev/null +++ b/test/warnstack.asm @@ -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" -- 2.11.4.GIT