mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 04:24:43 +00:00
gas: introduce .errif and .warnif
Rather than having people resort to indirect means to issue a certain kind of diagnostic conditionally upon an expression which can (or should) only be evaluated when all sections were sized and all symbols had their final values established, provide directives to directly achieve this.
This commit is contained in:
3
gas/NEWS
3
gas/NEWS
@@ -1,5 +1,8 @@
|
||||
-*- text -*-
|
||||
|
||||
* Add .errif and .warnif directives, permitting user-controlled diagnostics
|
||||
with conditionals that are evaluated only at the end of assembly.
|
||||
|
||||
* Predefined symbols "GAS(version)" and, on non-release builds, "GAS(date)" are
|
||||
now being made available.
|
||||
|
||||
|
||||
@@ -4582,6 +4582,7 @@ Some machine configurations provide additional directives.
|
||||
* Equiv:: @code{.equiv @var{symbol}, @var{expression}}
|
||||
* Eqv:: @code{.eqv @var{symbol}, @var{expression}}
|
||||
* Err:: @code{.err}
|
||||
* Errif:: @code{.errif @var{expression}}
|
||||
* Error:: @code{.error @var{string}}
|
||||
* Exitm:: @code{.exitm}
|
||||
* Extern:: @code{.extern}
|
||||
@@ -4714,6 +4715,7 @@ Some machine configurations provide additional directives.
|
||||
* VTableInherit:: @code{.vtable_inherit @var{child}, @var{parent}}
|
||||
@end ifset
|
||||
|
||||
* Warnif:: @code{.warnif @var{expression}}
|
||||
* Warning:: @code{.warning @var{string}}
|
||||
* Weak:: @code{.weak @var{names}}
|
||||
* Weakref:: @code{.weakref @var{alias}, @var{symbol}}
|
||||
@@ -5557,6 +5559,13 @@ If @command{@value{AS}} assembles a @code{.err} directive, it will print an erro
|
||||
message and, unless the @option{-Z} option was used, it will not generate an
|
||||
object file. This can be used to signal an error in conditionally compiled code.
|
||||
|
||||
@node Errif
|
||||
@section @code{.errif "@var{expression}"}
|
||||
@cindex errif directive
|
||||
|
||||
Record @var{expression} for evaluation at the end of assembly. Raise an error
|
||||
if the expression evaluates to non-zero.
|
||||
|
||||
@node Error
|
||||
@section @code{.error "@var{string}"}
|
||||
@cindex error directive
|
||||
@@ -7750,6 +7759,13 @@ parent whose addend is the value of the child symbol. As a special case the
|
||||
parent name of @code{0} is treated as referring to the @code{*ABS*} section.
|
||||
@end ifset
|
||||
|
||||
@node Warnif
|
||||
@section @code{.warnif "@var{expression}"}
|
||||
@cindex errif directive
|
||||
|
||||
Record @var{expression} for evaluation at the end of assembly. Raise a
|
||||
warning if the expression evaluates to non-zero.
|
||||
|
||||
@node Warning
|
||||
@section @code{.warning "@var{string}"}
|
||||
@cindex warning directive
|
||||
|
||||
59
gas/read.c
59
gas/read.c
@@ -236,6 +236,7 @@ static unsigned int bundle_lock_depth;
|
||||
static void do_s_func (int end_p, const char *default_prefix);
|
||||
static void s_altmacro (int);
|
||||
static void s_bad_end (int);
|
||||
static void s_errwarn_if (int);
|
||||
static void s_reloc (int);
|
||||
static int hex_float (int, char *);
|
||||
static segT get_known_segmented_expression (expressionS * expP);
|
||||
@@ -401,6 +402,7 @@ static const pseudo_typeS potable[] = {
|
||||
{"equiv", s_set, 1},
|
||||
{"eqv", s_set, -1},
|
||||
{"err", s_err, 0},
|
||||
{"errif", s_errwarn_if, 1},
|
||||
{"error", s_errwarn, 1},
|
||||
{"exitm", s_mexit, 0},
|
||||
/* extend */
|
||||
@@ -515,6 +517,7 @@ static const pseudo_typeS potable[] = {
|
||||
{"xdef", s_globl, 0},
|
||||
{"xref", s_ignore, 0},
|
||||
{"xstabs", s_xstab, 's'},
|
||||
{"warnif", s_errwarn_if, 0},
|
||||
{"warning", s_errwarn, 0},
|
||||
{"weakref", s_weakref, 0},
|
||||
{"word", cons, 2},
|
||||
@@ -2237,6 +2240,62 @@ s_errwarn (int err)
|
||||
demand_empty_rest_of_line ();
|
||||
}
|
||||
|
||||
/* Handle the .errif and .warnif pseudo-ops. */
|
||||
|
||||
static struct deferred_diag {
|
||||
struct deferred_diag *next;
|
||||
const char *file;
|
||||
unsigned int lineno;
|
||||
bool err;
|
||||
expressionS exp;
|
||||
} *deferred_diags, *last_deferred_diag;
|
||||
|
||||
static void
|
||||
s_errwarn_if (int err)
|
||||
{
|
||||
struct deferred_diag *diag = XNEW (struct deferred_diag);
|
||||
int errcnt = had_errors ();
|
||||
|
||||
deferred_expression (&diag->exp);
|
||||
if (errcnt != had_errors ())
|
||||
{
|
||||
ignore_rest_of_line ();
|
||||
return;
|
||||
}
|
||||
|
||||
diag->err = err;
|
||||
diag->file = as_where (&diag->lineno);
|
||||
diag->next = NULL;
|
||||
if ( deferred_diags == NULL )
|
||||
deferred_diags = diag;
|
||||
else
|
||||
last_deferred_diag->next = diag;
|
||||
last_deferred_diag = diag;
|
||||
|
||||
demand_empty_rest_of_line ();
|
||||
}
|
||||
|
||||
void
|
||||
evaluate_deferred_diags (void)
|
||||
{
|
||||
struct deferred_diag *diag;
|
||||
|
||||
for (diag = deferred_diags; diag != NULL; diag = diag->next)
|
||||
{
|
||||
if (!resolve_expression (&diag->exp) || diag->exp.X_op != O_constant)
|
||||
as_warn_where (diag->file, diag->lineno,
|
||||
_("expression does not evaluate to a constant"));
|
||||
else if (diag->exp.X_add_number == 0)
|
||||
continue;
|
||||
else if (diag->err)
|
||||
as_bad_where (diag->file, diag->lineno,
|
||||
_(".errif expression evaluates to true"));
|
||||
else
|
||||
as_warn_where (diag->file, diag->lineno,
|
||||
_(".warnif expression evaluates to true"));
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle the MRI fail pseudo-op. */
|
||||
|
||||
void
|
||||
|
||||
@@ -169,6 +169,7 @@ extern symbolS *s_comm_internal (int, symbolS *(*) (int, symbolS *, addressT));
|
||||
extern symbolS *s_lcomm_internal (int, symbolS *, addressT);
|
||||
extern void temp_ilp (char *);
|
||||
extern void restore_ilp (void);
|
||||
extern void evaluate_deferred_diags (void);
|
||||
extern void s_file_string (char *);
|
||||
|
||||
extern void s_abort (int) ATTRIBUTE_NORETURN;
|
||||
|
||||
6
gas/testsuite/gas/all/cond-diag.l
Normal file
6
gas/testsuite/gas/all/cond-diag.l
Normal file
@@ -0,0 +1,6 @@
|
||||
# This should match the output of gas cond-diag.s.
|
||||
.*: Assembler messages:
|
||||
.*:1: Error: non-constant .*
|
||||
.*:6: Error: backward ref .*
|
||||
.*:7: Warning: \.warning .*
|
||||
.*:4: Warning: \.warnif .*
|
||||
12
gas/testsuite/gas/all/cond-diag.s
Normal file
12
gas/testsuite/gas/all/cond-diag.s
Normal file
@@ -0,0 +1,12 @@
|
||||
.if end - start > 16
|
||||
.warning
|
||||
.endif
|
||||
.warnif end - start < 16
|
||||
.errif end - start >= 16
|
||||
.warnif 1b
|
||||
.warning
|
||||
|
||||
.data
|
||||
start:
|
||||
.uleb128 end - start
|
||||
end:
|
||||
@@ -488,6 +488,19 @@ switch -glob $target_triplet {
|
||||
}
|
||||
}
|
||||
|
||||
# This test uses a local label, which some targets don't support.
|
||||
# MeP can't deal with forward ref labels in .uleb128.
|
||||
switch -glob $target_triplet {
|
||||
*c54x*-*-* { }
|
||||
hppa*-*-* { }
|
||||
ia64-*-*vms* { }
|
||||
mep-*-* { }
|
||||
sh-*-pe* { }
|
||||
default {
|
||||
run_list_test "cond-diag"
|
||||
}
|
||||
}
|
||||
|
||||
gas_test_error "weakref2.s" "" "e: would close weakref loop: e => a => b => c => d => e"
|
||||
gas_test_error "weakref3.s" "" "a: would close weakref loop: a => b => c => d => e => a"
|
||||
gas_test_error "weakref4.s" "" "is already defined"
|
||||
|
||||
@@ -2321,6 +2321,8 @@ write_object_file (void)
|
||||
resolve_local_symbol_values ();
|
||||
resolve_reloc_expr_symbols ();
|
||||
|
||||
evaluate_deferred_diags ();
|
||||
|
||||
#ifdef OBJ_ELF
|
||||
if (IS_ELF)
|
||||
maybe_generate_build_notes ();
|
||||
|
||||
Reference in New Issue
Block a user