--- a/gas/NEWS
+++ b/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.
+
 * Add support for the x86 Intel MSR_IMM instructions.
 
 * Add support for the x86 Zhaoxin GMI instructions.
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -4577,6 +4577,7 @@ Some machine configurations provide addi
 * 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}
@@ -4709,6 +4710,7 @@ Some machine configurations provide addi
 * 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}}
@@ -5529,6 +5531,13 @@ If @command{@value{AS}} assembles a @cod
 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
@@ -7714,6 +7723,13 @@ parent whose addend is the value of 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
--- a/gas/read.c
+++ b/gas/read.c
@@ -257,6 +257,7 @@ static void do_s_func (int end_p, const
 static void s_align (int, int);
 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);
@@ -415,6 +416,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  */
@@ -529,6 +531,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},
@@ -2236,6 +2239,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 ();
+
+  latched_dot_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
--- a/gas/read.h
+++ b/gas/read.h
@@ -162,6 +162,7 @@ extern symbolS *s_comm_internal (int, sy
 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;
--- a/gas/write.c
+++ b/gas/write.c
@@ -2329,6 +2329,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 ();
--- /dev/null
+++ b/gas/testsuite/gas/all/cond-diag.l
@@ -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 .*
--- /dev/null
+++ b/gas/testsuite/gas/all/cond-diag.s
@@ -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:
--- a/gas/testsuite/gas/all/gas.exp
+++ b/gas/testsuite/gas/all/gas.exp
@@ -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"
