warnings: add [warning push] and [warning pop]
[nasm.git] / asm / error.c
blob4e86a0d73c4d4728537a487349fd457e9a699cbf
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2019 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
35 * error.c - error message handling routines for the assembler
38 #include "compiler.h"
41 #include "nasmlib.h"
42 #include "error.h"
44 /* Global error handling function */
45 vefunc nasm_verror;
47 /* Common function body */
48 #define nasm_do_error(s) \
49 va_list ap; \
50 va_start(ap, fmt); \
51 nasm_verror((s), fmt, ap); \
52 va_end(ap);
54 void nasm_error(errflags severity, const char *fmt, ...)
56 nasm_do_error(severity);
59 #define nasm_err_helpers(_type, _name, _sev) \
60 _type nasm_ ## _name ## f (errflags flags, const char *fmt, ...) \
61 { \
62 nasm_do_error((_sev)|flags); \
63 if (_sev >= ERR_FATAL) \
64 abort(); \
65 } \
66 _type nasm_ ## _name (const char *fmt, ...) \
67 { \
68 nasm_do_error(_sev); \
69 if (_sev >= ERR_FATAL) \
70 abort(); \
73 nasm_err_helpers(void, debug, ERR_DEBUG)
74 nasm_err_helpers(void, note, ERR_NOTE)
75 nasm_err_helpers(void, nonfatal, ERR_NONFATAL)
76 nasm_err_helpers(fatal_func, fatal, ERR_FATAL)
77 nasm_err_helpers(fatal_func, panic, ERR_PANIC)
80 * Strongly discourage warnings without level by require flags on warnings.
81 * This means nasm_warn() is the equivalent of the -f variants of the
82 * other ones.
84 void nasm_warn(errflags severity, const char *fmt, ...)
86 nasm_do_error(ERR_WARNING|severity);
89 fatal_func nasm_panic_from_macro(const char *file, int line)
91 nasm_panic("internal error at %s:%d\n", file, line);
94 fatal_func nasm_assert_failed(const char *file, int line, const char *msg)
96 nasm_panic("assertion %s failed at %s:%d", msg, file, line);
101 * Warning stack management. Note that there is an implicit "push"
102 * after the command line has been parsed, but this particular push
103 * cannot be popped.
105 struct warning_stack {
106 struct warning_stack *next;
107 uint8_t state[sizeof warning_state];
109 static struct warning_stack *warning_stack, *warning_state_init;
111 /* Push the warning status onto the warning stack */
112 void push_warnings(void)
114 struct warning_stack *ws;
116 ws = nasm_malloc(sizeof *ws);
117 memcpy(ws->state, warning_state, sizeof warning_state);
118 ws->next = warning_stack;
119 warning_stack = ws;
122 /* Pop the warning status off the warning stack */
123 void pop_warnings(void)
125 struct warning_stack *ws = warning_stack;
127 memcpy(warning_state, ws->state, sizeof warning_state);
128 if (!ws->next) {
130 *!warn-stack-empty [on] warning stack empty
131 *! a [WARNING POP] directive was executed when
132 *! the warning stack is empty. This is treated
133 *! as a [WARNING *all] directive.
135 nasm_warn(WARN_WARN_STACK_EMPTY, "warning stack empty");
136 } else {
137 warning_stack = ws->next;
138 nasm_free(ws);
142 /* Call after the command line is parsed, but before the first pass */
143 void init_warnings(void)
145 push_warnings();
146 warning_state_init = warning_stack;
150 /* Call after each pass */
151 void reset_warnings(void)
153 struct warning_stack *ws = warning_stack;
155 /* Unwind the warning stack. We do NOT delete the last entry! */
156 while (ws->next) {
157 struct warning_stack *wst = ws;
158 ws = ws->next;
159 nasm_free(wst);
161 warning_stack = ws;
162 memcpy(warning_state, ws->state, sizeof warning_state);
166 * This is called when processing a -w or -W option, or a warning directive.
167 * Returns on if if the action was successful.
169 * Special pseudo-warnings:
171 *!other [on] any warning not specifially mentioned above
172 *! specifies any warning not included in any specific warning class.
174 *!all [all] all possible warnings
175 *! is an alias for \e{all} suppressible warning classes.
176 *! Thus, \c{-w+all} enables all available warnings, and \c{-w-all}
177 *! disables warnings entirely (since NASM 2.13).
179 bool set_warning_status(const char *value)
181 enum warn_action { WID_OFF, WID_ON, WID_RESET };
182 enum warn_action action;
183 const char *name;
184 bool ok = false;
185 uint8_t mask;
186 int i;
188 value = nasm_skip_spaces(value);
190 switch (*value) {
191 case '-':
192 action = WID_OFF;
193 value++;
194 break;
195 case '+':
196 action = WID_ON;
197 value++;
198 break;
199 case '*':
200 action = WID_RESET;
201 value++;
202 break;
203 case 'N':
204 case 'n':
205 if (!nasm_strnicmp(value, "no-", 3)) {
206 action = WID_OFF;
207 value += 3;
208 break;
209 } else if (!nasm_stricmp(value, "none")) {
210 action = WID_OFF;
211 value = NULL;
212 break;
214 /* else fall through */
215 default:
216 action = WID_ON;
217 break;
220 mask = WARN_ST_ENABLED;
222 if (value && !nasm_strnicmp(value, "error", 5)) {
223 switch (value[5]) {
224 case '=':
225 mask = WARN_ST_ERROR;
226 value += 6;
227 break;
228 case '\0':
229 mask = WARN_ST_ERROR;
230 value = NULL;
231 break;
232 default:
233 /* Just an accidental prefix? */
234 break;
238 name = value ? value : "<none>";
239 if (value && !nasm_stricmp(value, "all"))
240 value = NULL;
242 /* This is inefficient, but it shouldn't matter... */
243 for (i = 1; i < WARN_IDX_ALL; i++) {
244 if (!value || !nasm_stricmp(value, warning_name[i])) {
245 ok = true; /* At least one action taken */
246 switch (action) {
247 case WID_OFF:
248 warning_state[i] &= ~mask;
249 break;
250 case WID_ON:
251 warning_state[i] |= mask;
252 break;
253 case WID_RESET:
254 warning_state[i] &= ~mask;
255 warning_state[i] |=
256 warning_state_init->state[i] & mask;
257 break;
262 if (!ok) {
264 *!unknown-warning [off] unknown warning in -W/-w or warning directive
265 *! warns about a \c{-w} or \c{-W} option or a \c{[WARNING]} directive
266 *! that contains an unknown warning name or is otherwise not possible to process.
268 nasm_warn(WARN_UNKNOWN_WARNING, "unknown warning name: %s", name);
271 return ok;