diff --git a/asm/labels.c b/asm/labels.c index d0904ad3..a3ed0066 100644 --- a/asm/labels.c +++ b/asm/labels.c @@ -506,17 +506,18 @@ void define_label(const char *label, int32_t segment, nasm_error(ERR_NONFATAL, "label `%s' inconsistently redefined", lptr->defn.label); - noteflags = ERR_NOTE; + noteflags = ERR_NOTE|ERR_HERE; } else { nasm_error(ERR_WARNING|WARN_LABEL_REDEF|ERR_PASS2, "label `%s' redefined to an identical value", lptr->defn.label); - noteflags = ERR_NOTE|WARN_LABEL_REDEF|ERR_PASS2; + noteflags = ERR_NOTE|ERR_HERE|WARN_LABEL_REDEF|ERR_PASS2; } src_get(&saved_line, &saved_fname); src_set(lptr->defn.def_line, lptr->defn.def_file); - nasm_error(noteflags, "label `%s' originally defined here", lptr->defn.label); + nasm_error(noteflags, "label `%s' originally defined", + lptr->defn.label); src_set(saved_line, saved_fname); } else if (changed && pass0 > 1 && lptr->defn.type != LBL_SPECIAL) { /* diff --git a/asm/listing.c b/asm/listing.c index fe7c5e92..4d753dbd 100644 --- a/asm/listing.c +++ b/asm/listing.c @@ -331,27 +331,27 @@ static void list_downlevel(int type) } } -static void list_error(int severity, const char *pfx, const char *msg) +static void list_error(int severity, const char *fmt, ...) { - size_t l1, l2; struct list_error *le; - char *p; + va_list ap; + int len; if (!listfp) return; - l1 = strlen(pfx); - l2 = strlen(msg); + va_start(ap, fmt); + len = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); /* sizeof(*le) already accounts for the final NULL */ - le = nasm_malloc(sizeof(*le) + l1 + l2); + le = nasm_malloc(sizeof(*le) + len); + + va_start(ap, fmt); + vsnprintf(le->str, len+1, fmt, ap); + va_end(ap); le->next = NULL; - p = le->str; - p = mempcpy(p, pfx, l1); - p = mempcpy(p, msg, l2); - *p = '\0'; - *listerr_tail = le; listerr_tail = &le->next; diff --git a/asm/listing.h b/asm/listing.h index df88e8a8..f3ddb0e0 100644 --- a/asm/listing.h +++ b/asm/listing.h @@ -96,7 +96,7 @@ struct lfmt { /* * Called on a warning or error, with the error message. */ - void (*error)(int severity, const char *pfx, const char *msg); + void printf_func(2, 3) (*error)(int severity, const char *fmt, ...); /* * Update the current offset. Used to give the listing generator diff --git a/asm/nasm.c b/asm/nasm.c index 100e4b9c..ddc3404e 100644 --- a/asm/nasm.c +++ b/asm/nasm.c @@ -1768,21 +1768,35 @@ static bool skip_this_pass(int severity) */ static bool is_suppressed(int severity) { + if ((severity & ERR_MASK) >= ERR_FATAL) + return false; /* Fatal errors can never be suppressed */ + return !(warning_state[warn_index(severity)] & WARN_ST_ENABLED); } /** - * check if we have a warning that should be promoted to an error + * Return the true error type (the ERR_MASK part) of the given + * severity, accounting for warnings that may need to be promoted to + * error. * * @param severity the severity of the warning or error - * @return true if we should promote to error + * @return true if we should error out */ -static bool warning_is_error(int severity) +static int true_error_type(int severity) { - if ((severity & ERR_MASK) != ERR_WARNING) - return false; /* Other message types */ + const uint8_t warn_is_err = WARN_ST_ENABLED|WARN_ST_ERROR; + int type; - return !!(warning_state[warn_index(severity)] & WARN_ST_ERROR); + type = severity & ERR_MASK; + + /* Promote warning to error? */ + if (type == ERR_WARNING) { + uint8_t state = warning_state[warn_index(severity)]; + if ((state & warn_is_err) == warn_is_err) + type = ERR_NONFATAL; + } + + return type; } /** @@ -1798,10 +1812,17 @@ static bool warning_is_error(int severity) static void nasm_verror_asm(int severity, const char *fmt, va_list args) { char msg[1024]; + char warnsuf[64]; + char linestr[64]; const char *pfx; - bool warn_is_err = warning_is_error(severity); + int spec_type = severity & ERR_MASK; /* type originally specified */ + int true_type = true_error_type(severity); const char *currentfile = NULL; int32_t lineno = 0; + static const char * const pfx_table[ERR_MASK+1] = { + "debug: ", "note: ", "warning: ", "error: ", + "", "", "fatal: ", "panic: " + }; if (is_suppressed(severity)) return; @@ -1816,53 +1837,38 @@ static void nasm_verror_asm(int severity, const char *fmt, va_list args) lineno = 0; } } - if (!currentfile) - currentfile = "nasm"; - switch (severity & (ERR_MASK|ERR_NO_SEVERITY)) { - case ERR_NOTE: - pfx = "note: "; - break; - case ERR_WARNING: - if (!warn_is_err) { - pfx = "warning: "; - break; - } - /* fall through */ - case ERR_NONFATAL: - pfx = "error: "; - break; - case ERR_FATAL: - pfx = "fatal: "; - break; - case ERR_PANIC: - pfx = "panic: "; - break; - case ERR_DEBUG: - pfx = "debug: "; - break; - default: + /* + * For a debug/warning/note event, if ERR_HERE is set don't + * output anything if there is no current filename available + */ + if (!currentfile && (severity & ERR_HERE) && true_type <= ERR_WARNING) + return; + + if (severity & ERR_NO_SEVERITY) pfx = ""; - break; - } + else + pfx = pfx_table[true_type]; - vsnprintf(msg, sizeof msg - 64, fmt, args); - if ((severity & ERR_MASK) == ERR_WARNING && !is_suppressed(severity)) { - char *p = strchr(msg, '\0'); - snprintf(p, 64, " [-w+%s%s]", - warn_is_err ? "error=" : "", + vsnprintf(msg, sizeof msg, fmt, args); + *warnsuf = 0; + if (spec_type == ERR_WARNING) { + snprintf(warnsuf, sizeof warnsuf, " [-w+%s%s]", + true_type ? "error=" : "", warnings[warn_index(severity)].name); } + *linestr = 0; + if (lineno) { + snprintf(linestr, sizeof linestr, "%s%"PRId32"%s", + errfmt->beforeline, lineno, errfmt->afterline); + } + if (!skip_this_pass(severity)) { - if (!lineno) { - fprintf(error_file, "%s%s%s%s\n", - currentfile, errfmt->beforemsg, pfx, msg); - } else { - fprintf(error_file, "%s%s%"PRId32"%s%s%s%s\n", - currentfile, errfmt->beforeline, lineno, - errfmt->afterline, errfmt->beforemsg, pfx, msg); - } + fprintf(error_file, "%s%s%s%s%s%s%s\n", + currentfile ? currentfile : "nasm", + linestr, errfmt->beforemsg, pfx, msg, + (severity & ERR_HERE) ? " here" : "", warnsuf); } /* Are we recursing from error_list_macros? */ @@ -1873,7 +1879,19 @@ static void nasm_verror_asm(int severity, const char *fmt, va_list args) * Don't suppress this with skip_this_pass(), or we don't get * pass1 or preprocessor warnings in the list file */ - lfmt->error(severity, pfx, msg); + if (severity & ERR_HERE) { + if (lineno) + lfmt->error(severity, "%s%s at %s:%"PRId32"%s", + pfx, msg, currentfile, lineno, warnsuf); + else if (currentfile) + lfmt->error(severity, "%s%s in file %s%s", + pfx, msg, currentfile, warnsuf); + else + lfmt->error(severity, "%s%s in unknown location%s", + pfx, msg, warnsuf); + } else { + lfmt->error(severity, "%s%s%s", pfx, msg, warnsuf); + } if (skip_this_pass(severity)) return; @@ -1883,15 +1901,11 @@ static void nasm_verror_asm(int severity, const char *fmt, va_list args) preproc->error_list_macros(severity); - switch (severity & ERR_MASK) { + switch (true_type) { case ERR_NOTE: case ERR_DEBUG: - /* no further action, by definition */ - break; case ERR_WARNING: - /* Treat warnings as errors */ - if (warning_is_error(severity)) - terminate_after_phase = true; + /* no further action, by definition */ break; case ERR_NONFATAL: terminate_after_phase = true; diff --git a/asm/preproc.c b/asm/preproc.c index 3b8de02b..b134414a 100644 --- a/asm/preproc.c +++ b/asm/preproc.c @@ -5451,7 +5451,7 @@ static void pp_list_one_macro(MMacro *m, int severity) if (m->name && !m->nolist) { src_set(m->xline + m->lineno, m->fname); - nasm_error(severity, "... from macro `%s' defined here", m->name); + nasm_error(severity, "... from macro `%s' defined", m->name); } } @@ -5460,7 +5460,7 @@ static void pp_error_list_macros(int severity) int32_t saved_line; const char *saved_fname = NULL; - severity |= ERR_PP_LISTMACRO | ERR_NO_SEVERITY; + severity |= ERR_PP_LISTMACRO | ERR_NO_SEVERITY | ERR_HERE; src_get(&saved_line, &saved_fname); if (istk) diff --git a/include/error.h b/include/error.h index d2f04f4c..5a676e67 100644 --- a/include/error.h +++ b/include/error.h @@ -72,6 +72,7 @@ static inline vefunc nasm_set_verror(vefunc ve) * and dump core for reference */ #define ERR_MASK 0x00000007 /* mask off the above codes */ #define ERR_NOFILE 0x00000010 /* don't give source file name/line */ +#define ERR_HERE 0x00000020 /* point to a specific source location */ #define ERR_USAGE 0x00000040 /* print a usage message */ #define ERR_PASS1 0x00000080 /* only print this error on pass 1 */ #define ERR_PASS2 0x00000100 /* only print this error on pass 2 */