diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6ab7b701cd2041324aaea62ef679eff36f99f902..554829aa4cbc6e5f003e24f8a17e5d80fc224d7c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2004-02-19  Richard Henderson  <rth@redhat.com>
+
+	* Makefile.in (STRICT2_WARN): Add -Wno-variadic-macros.
+	* tree.c (build0, build1, build2, build3, build4): Split out from...
+	(build): ... here.  Call them.
+	* tree.h (build, _buildN1, _buildN2, _buildC1, _buildC2): New.
+
+	* convert.c (convert_to_integer): Remove extra build argument.
+	* tree-inline.c (expand_call_inline): Likewise.
+
 2004-02-19  Richard Henderson  <rth@redhat.com>
 
 	* c-opts.c (warn_variadic_macros): New.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 8236efa893b07ad3046bdb8044ad8881d5a28e49..3f65e604d4cb4ba0000e7d29511836c9ddaa5bd9 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -159,10 +159,12 @@ coverageexts = .{gcda,gcno}
 # STRICT_WARN and STRICT2_WARN are the additional warning flags to
 # apply to the back end and the C front end, which may be compiled
 # with other compilers.  This is partially controlled by configure in
-# stage1, as not all versions of gcc understand -Wno-long-long.
+# stage1, as not all versions of gcc understand -Wno-long-long or
+# -Wno-variadic-macros.
 LOOSE_WARN = -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes
 STRICT_WARN = @strict1_warn@
-STRICT2_WARN = -pedantic -Wno-long-long -Wold-style-definition @WERROR@
+STRICT2_WARN = -pedantic -Wno-long-long -Wold-style-definition \
+  -Wno-variadic-macros @WERROR@
 
 # This is set by --enable-checking.  The idea is to catch forgotten
 # "extern" tags in header files.
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index 1fa6259305587a8c6dfd3e2ef21b9120f3984d2d..59bed8f0c8cf03805df2cce61431bccd644f918d 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,3 +1,7 @@
+2004-02-19  Richard Henderson  <rth@redhat.com>
+
+	* misc.c (record_code_position): Add third build arg for RTL_EXPR.
+
 2004-02-18  Emmanuel Briot  <briot@act-europe.fr>
 
 	* ali.ads, ali.adb (First_Sdep_Entry): No longer a constant, so that
diff --git a/gcc/ada/misc.c b/gcc/ada/misc.c
index 6a40590df9f02a1520726b4af06e84aaf18e6699..a87331d23f2fea2262b86e062e0376b5258c4d75 100644
--- a/gcc/ada/misc.c
+++ b/gcc/ada/misc.c
@@ -804,7 +804,7 @@ record_code_position (Node_Id gnat_node)
        addressable needs some fixups and also for above reason.  */
     save_gnu_tree (gnat_node,
 		   build (RTL_EXPR, void_type_node, NULL_TREE,
-			  (tree) emit_note (NOTE_INSN_DELETED)),
+			  (tree) emit_note (NOTE_INSN_DELETED), NULL_TREE),
 		   1);
 }
 
diff --git a/gcc/convert.c b/gcc/convert.c
index 9096541fe2a110d45911b69216b38f0076dd6e43..8fca41579637ffba0834c44298f16d49c9b22765 100644
--- a/gcc/convert.c
+++ b/gcc/convert.c
@@ -523,8 +523,7 @@ convert_to_integer (tree type, tree expr)
 		    return convert (type,
 				    fold (build (ex_form, typex,
 						 convert (typex, arg0),
-						 convert (typex, arg1),
-						 0)));
+						 convert (typex, arg1))));
 		  }
 	      }
 	  }
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog
index 63d844b5de31c0865c10e583042b3be25882417f..a0568c7084ba894c4195ff092daf1d04be26e1cd 100644
--- a/gcc/java/ChangeLog
+++ b/gcc/java/ChangeLog
@@ -1,3 +1,7 @@
+2004-02-19  Richard Henderson  <rth@redhat.com>
+
+	* parse.y (switch_label): Use make_node for DEFAULT_EXPR.
+
 2004-02-16  Geoffrey Keating  <geoffk@apple.com>
 
 	* Make-lang.in (java.install-man): Add extra dependencies.
diff --git a/gcc/java/parse.y b/gcc/java/parse.y
index 390b8cdaefd5bf87b0bb6f3afca3a0d68583c825..72cc9f3d103c37f9a4a7dfb969d13ac789d37b5f 100644
--- a/gcc/java/parse.y
+++ b/gcc/java/parse.y
@@ -1635,7 +1635,7 @@ switch_label:
 		}
 |	DEFAULT_TK REL_CL_TK
 		{
-		  tree lab = build (DEFAULT_EXPR, NULL_TREE, NULL_TREE);
+		  tree lab = make_node (DEFAULT_EXPR);
 		  EXPR_WFL_LINECOL (lab) = $1.location;
 		  java_method_add_stmt (current_function_decl, lab);
 		}
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index ce0b415fe057750418d305adb1360710444e8bf5..42da58b29f28c04aa55b54e904e98d1731404c4d 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -1377,7 +1377,7 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
      statements within the function to jump to.  The type of the
      statement expression is the return type of the function call.  */
   stmt = NULL;
-  expr = build (BLOCK, TREE_TYPE (TREE_TYPE (fn)), stmt);
+  expr = build (BLOCK, TREE_TYPE (TREE_TYPE (fn)));
 #endif /* INLINER_FOR_JAVA */
 
   /* Local declarations will be replaced by their equivalents in this
diff --git a/gcc/tree.c b/gcc/tree.c
index c02b1004b917b1285c67c153bb658414e75b73a6..d2b79bcca3cfc211eb4174fc62c73e670fbc4e21 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -2286,127 +2286,31 @@ stabilize_reference_1 (tree e)
 
 /* Low-level constructors for expressions.  */
 
-/* Build an expression of code CODE, data type TYPE,
-   and operands as specified by the arguments ARG1 and following arguments.
-   Expressions and reference nodes can be created this way.
-   Constants, decls, types and misc nodes cannot be.  */
+/* Build an expression of code CODE, data type TYPE, and operands as
+   specified.  Expressions and reference nodes can be created this way.
+   Constants, decls, types and misc nodes cannot be.
+
+   We define 5 non-variadic functions, from 0 to 4 arguments.  This is
+   enough for all extant tree codes.  These functions can be called 
+   directly (preferably!), but can also be obtained via GCC preprocessor
+   magic within the build macro.  */
 
 tree
-build (enum tree_code code, tree tt, ...)
+build0 (enum tree_code code, tree tt)
 {
   tree t;
-  int length;
-  int i;
-  int fro;
-  int constant;
-  va_list p;
-  tree node;
 
-  va_start (p, tt);
+#ifdef ENABLE_CHECKING
+  if (TREE_CODE_LENGTH (code) != 0)
+    abort ();
+#endif
 
   t = make_node (code);
-  length = TREE_CODE_LENGTH (code);
   TREE_TYPE (t) = tt;
 
-  /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY for the
-     result based on those same flags for the arguments.  But if the
-     arguments aren't really even `tree' expressions, we shouldn't be trying
-     to do this.  */
-  fro = first_rtl_op (code);
-
-  /* Expressions without side effects may be constant if their
-     arguments are as well.  */
-  constant = (TREE_CODE_CLASS (code) == '<'
-	      || TREE_CODE_CLASS (code) == '1'
-	      || TREE_CODE_CLASS (code) == '2'
-	      || TREE_CODE_CLASS (code) == 'c');
-
-  if (length == 2)
-    {
-      /* This is equivalent to the loop below, but faster.  */
-      tree arg0 = va_arg (p, tree);
-      tree arg1 = va_arg (p, tree);
-
-      TREE_OPERAND (t, 0) = arg0;
-      TREE_OPERAND (t, 1) = arg1;
-      TREE_READONLY (t) = 1;
-      if (arg0 && fro > 0)
-	{
-	  if (TREE_SIDE_EFFECTS (arg0))
-	    TREE_SIDE_EFFECTS (t) = 1;
-	  if (!TREE_READONLY (arg0))
-	    TREE_READONLY (t) = 0;
-	  if (!TREE_CONSTANT (arg0))
-	    constant = 0;
-	}
-
-      if (arg1 && fro > 1)
-	{
-	  if (TREE_SIDE_EFFECTS (arg1))
-	    TREE_SIDE_EFFECTS (t) = 1;
-	  if (!TREE_READONLY (arg1))
-	    TREE_READONLY (t) = 0;
-	  if (!TREE_CONSTANT (arg1))
-	    constant = 0;
-	}
-    }
-  else if (length == 1)
-    {
-      tree arg0 = va_arg (p, tree);
-
-      /* The only one-operand cases we handle here are those with side-effects.
-	 Others are handled with build1.  So don't bother checked if the
-	 arg has side-effects since we'll already have set it.
-
-	 ??? This really should use build1 too.  */
-      if (TREE_CODE_CLASS (code) != 's')
-	abort ();
-      TREE_OPERAND (t, 0) = arg0;
-    }
-  else
-    {
-      for (i = 0; i < length; i++)
-	{
-	  tree operand = va_arg (p, tree);
-
-	  TREE_OPERAND (t, i) = operand;
-	  if (operand && fro > i)
-	    {
-	      if (TREE_SIDE_EFFECTS (operand))
-		TREE_SIDE_EFFECTS (t) = 1;
-	      if (!TREE_CONSTANT (operand))
-		constant = 0;
-	    }
-	}
-    }
-  va_end (p);
-
-  TREE_CONSTANT (t) = constant;
-  
-  if (code == CALL_EXPR && !TREE_SIDE_EFFECTS (t))
-    {
-      /* Calls have side-effects, except those to const or
-	 pure functions.  */
-      i = call_expr_flags (t);
-      if (!(i & (ECF_CONST | ECF_PURE)))
-	TREE_SIDE_EFFECTS (t) = 1;
-
-      /* And even those have side-effects if their arguments do.  */
-      else for (node = TREE_OPERAND (t, 1); node; node = TREE_CHAIN (node))
-	if (TREE_SIDE_EFFECTS (TREE_VALUE (node)))
-	  {
-	    TREE_SIDE_EFFECTS (t) = 1;
-	    break;
-	  }
-    }
-
   return t;
 }
 
-/* Same as above, but only builds for unary operators.
-   Saves lions share of calls to `build'; cuts down use
-   of varargs, which is expensive for RISC machines.  */
-
 tree
 build1 (enum tree_code code, tree type, tree node)
 {
@@ -2435,9 +2339,7 @@ build1 (enum tree_code code, tree type, tree node)
 #endif
 
 #ifdef ENABLE_CHECKING
-  if (TREE_CODE_CLASS (code) == '2'
-      || TREE_CODE_CLASS (code) == '<'
-      || TREE_CODE_LENGTH (code) != 1)
+  if (TREE_CODE_LENGTH (code) != 1)
     abort ();
 #endif /* ENABLE_CHECKING */
 
@@ -2512,6 +2414,191 @@ build1 (enum tree_code code, tree type, tree node)
   return t;
 }
 
+#define PROCESS_ARG(N)			\
+  do {					\
+    TREE_OPERAND (t, N) = arg##N;	\
+    if (arg##N && fro > N)		\
+      {					\
+        if (TREE_SIDE_EFFECTS (arg##N))	\
+	  side_effects = 1;		\
+        if (!TREE_READONLY (arg##N))	\
+	  read_only = 0;		\
+        if (!TREE_CONSTANT (arg##N))	\
+	  constant = 0;			\
+      }					\
+  } while (0)
+
+tree
+build2 (enum tree_code code, tree tt, tree arg0, tree arg1)
+{
+  bool constant, read_only, side_effects;
+  tree t;
+  int fro;
+
+#ifdef ENABLE_CHECKING
+  if (TREE_CODE_LENGTH (code) != 2)
+    abort ();
+#endif
+
+  t = make_node (code);
+  TREE_TYPE (t) = tt;
+
+  /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY for the
+     result based on those same flags for the arguments.  But if the
+     arguments aren't really even `tree' expressions, we shouldn't be trying
+     to do this.  */
+  fro = first_rtl_op (code);
+
+  /* Expressions without side effects may be constant if their
+     arguments are as well.  */
+  constant = (TREE_CODE_CLASS (code) == '<'
+	      || TREE_CODE_CLASS (code) == '2');
+  read_only = 1;
+  side_effects = TREE_SIDE_EFFECTS (t);
+
+  PROCESS_ARG(0);
+  PROCESS_ARG(1);
+
+  if (code == CALL_EXPR && !side_effects)
+    {
+      tree node;
+      int i;
+
+      /* Calls have side-effects, except those to const or
+	 pure functions.  */
+      i = call_expr_flags (t);
+      if (!(i & (ECF_CONST | ECF_PURE)))
+	side_effects = 1;
+
+      /* And even those have side-effects if their arguments do.  */
+      else for (node = TREE_OPERAND (t, 1); node; node = TREE_CHAIN (node))
+	if (TREE_SIDE_EFFECTS (TREE_VALUE (node)))
+	  {
+	    side_effects = 1;
+	    break;
+	  }
+    }
+
+  TREE_READONLY (t) = read_only;
+  TREE_CONSTANT (t) = constant;
+  TREE_SIDE_EFFECTS (t) = side_effects;  
+
+  return t;
+}
+
+tree
+build3 (enum tree_code code, tree tt, tree arg0, tree arg1, tree arg2)
+{
+  bool constant, read_only, side_effects;
+  tree t;
+  int fro;
+
+  /* ??? Quite a lot of existing code passes one too many arguments to
+     CALL_EXPR.  Not going to fix them, because CALL_EXPR is about to
+     grow a new argument, so it would just mean changing them back.  */
+  if (code == CALL_EXPR)
+    {
+      if (arg2 != NULL_TREE)
+	abort ();
+      return build2 (code, tt, arg0, arg1);
+    }
+
+#ifdef ENABLE_CHECKING
+  if (TREE_CODE_LENGTH (code) != 3)
+    abort ();
+#endif
+
+  t = make_node (code);
+  TREE_TYPE (t) = tt;
+
+  fro = first_rtl_op (code);
+
+  side_effects = TREE_SIDE_EFFECTS (t);
+
+  PROCESS_ARG(0);
+  PROCESS_ARG(1);
+  PROCESS_ARG(2);
+
+  TREE_SIDE_EFFECTS (t) = side_effects;  
+
+  return t;
+}
+
+tree
+build4 (enum tree_code code, tree tt, tree arg0, tree arg1,
+	tree arg2, tree arg3)
+{
+  bool constant, read_only, side_effects;
+  tree t;
+  int fro;
+
+#ifdef ENABLE_CHECKING
+  if (TREE_CODE_LENGTH (code) != 4)
+    abort ();
+#endif
+
+  t = make_node (code);
+  TREE_TYPE (t) = tt;
+
+  fro = first_rtl_op (code);
+
+  side_effects = TREE_SIDE_EFFECTS (t);
+
+  PROCESS_ARG(0);
+  PROCESS_ARG(1);
+  PROCESS_ARG(2);
+  PROCESS_ARG(3);
+
+  TREE_SIDE_EFFECTS (t) = side_effects;  
+
+  return t;
+}
+
+/* Backup definition for non-gcc build compilers.  */
+
+tree
+(build) (enum tree_code code, tree tt, ...)
+{
+  tree t, arg0, arg1, arg2, arg3;
+  int length = TREE_CODE_LENGTH (code);
+  va_list p;
+
+  va_start (p, tt);
+  switch (length)
+    {
+    case 0:
+      t = build0 (code, tt);
+      break;
+    case 1:
+      arg0 = va_arg (p, tree);
+      t = build1 (code, tt, arg0);
+      break;
+    case 2:
+      arg0 = va_arg (p, tree);
+      arg1 = va_arg (p, tree);
+      t = build2 (code, tt, arg0, arg1);
+      break;
+    case 3:
+      arg0 = va_arg (p, tree);
+      arg1 = va_arg (p, tree);
+      arg2 = va_arg (p, tree);
+      t = build3 (code, tt, arg0, arg1, arg2);
+      break;
+    case 4:
+      arg0 = va_arg (p, tree);
+      arg1 = va_arg (p, tree);
+      arg2 = va_arg (p, tree);
+      arg3 = va_arg (p, tree);
+      t = build4 (code, tt, arg0, arg1, arg2, arg3);
+      break;
+    default:
+      abort ();
+    }
+  va_end (p);
+
+  return t;
+}
+
 /* Similar except don't specify the TREE_TYPE
    and leave the TREE_SIDE_EFFECTS as 0.
    It is permissible for arguments to be null,
diff --git a/gcc/tree.h b/gcc/tree.h
index ee1f50c8c09858568af7cd988d16f134bf3e4cdf..25ba23a211e56c661fc54dfb516870814d10fb39 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2112,13 +2112,30 @@ extern tree maybe_get_identifier (const char *);
 extern tree build (enum tree_code, tree, ...);
 extern tree build_nt (enum tree_code, ...);
 
+#if GCC_VERSION >= 3000 || __STDC_VERSION__ >= 199901L
+/* Use preprocessor trickery to map "build" to "buildN" where N is the
+   expected number of arguments.  This is used for both efficiency (no
+   varargs), and checking (verifying number of passed arguments).  */
+#define build(code, ...) \
+  _buildN1(build, _buildC1(__VA_ARGS__))(code, __VA_ARGS__)
+#define _buildN1(BASE, X)	_buildN2(BASE, X)
+#define _buildN2(BASE, X)	BASE##X
+#define _buildC1(...)		_buildC2(__VA_ARGS__,9,8,7,6,5,4,3,2,1,0,0)
+#define _buildC2(x,a1,a2,a3,a4,a5,a6,a7,a8,a9,c,...) c
+#endif
+
+extern tree build0 (enum tree_code, tree);
+extern tree build1 (enum tree_code, tree, tree);
+extern tree build2 (enum tree_code, tree, tree, tree);
+extern tree build3 (enum tree_code, tree, tree, tree, tree);
+extern tree build4 (enum tree_code, tree, tree, tree, tree, tree);
+
 extern tree build_int_2_wide (unsigned HOST_WIDE_INT, HOST_WIDE_INT);
 extern tree build_vector (tree, tree);
 extern tree build_constructor (tree, tree);
 extern tree build_real_from_int_cst (tree, tree);
 extern tree build_complex (tree, tree, tree);
 extern tree build_string (int, const char *);
-extern tree build1 (enum tree_code, tree, tree);
 extern tree build_tree_list (tree, tree);
 extern tree build_decl (enum tree_code, tree, tree);
 extern tree build_block (tree, tree, tree, tree, tree);