Subject: bug#19634: counting MANY function args more reliably

From: Paul Eggert <[email-masked]>
Date: Tue, 20 Jan 2015 01:26:25 -0800

Commit ef5a526f1b51b76b0f753e0936c80743a7f4463d fixed a bug in Emacs where the C 
code passed 10 arguments to a function using the MANY calling convention, but 
the caller mistakenly passed 8 as the argument count, and this mistakenly 
discarded the last two arguments; see <http://bugs.gnu.org/3228#63>.

To help prevent this sort of mistake in the future, I would like to install 
something like the attached patch, which uses a new C macro CALLN to count these 
arguments automatically.  The key lines in the patch are the following additions 
to lisp.h:

#define CALLMANY(f, array) (f) (ARRAYELTS (array), array)

#define CALLN(f, ...) CALLMANY (f, ((Lisp_Object []) {__VA_ARGS__}))

This lets code use 'return CALLN (foo, a, b, c, d);' instead of the current 
error-prone usages which are like '{ Lisp_Object args[4]; args[0] = a; args[1] = 
b; args[2] = c; args[3] = d; return foo (3, args); }'.  (Oops, that last '3' 
should have been a '4'....)

This patch still needs a ChangeLog entry and some more testing on my part, but I 
thought I'd get it out for review now.
diff --git a/src/alloc.c b/src/alloc.c
index d758ca1..7ac7a12 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -4412,19 +4412,17 @@ DEFUN ("gc-status", Fgc_status, Sgc_status, 0, 0, "",
        doc: /* Show information about live and zombie objects.  */)
   (void)
 {
-  Lisp_Object args[8], zombie_list = Qnil;
-  EMACS_INT i;
-  for (i = 0; i < min (MAX_ZOMBIES, nzombies); i++)
+  Lisp_Object zombie_list = Qnil;
+  for (int i = 0; i < min (MAX_ZOMBIES, nzombies); i++)
     zombie_list = Fcons (zombies[i], zombie_list);
-  args[0] = build_string ("%d GCs, avg live/zombies = %.2f/%.2f (%f%%), max %d/%d\nzombies: %S");
-  args[1] = make_number (ngcs);
-  args[2] = make_float (avg_live);
-  args[3] = make_float (avg_zombies);
-  args[4] = make_float (avg_zombies / avg_live / 100);
-  args[5] = make_number (max_live);
-  args[6] = make_number (max_zombies);
-  args[7] = zombie_list;
-  return Fmessage (8, args);
+  return CALLN (Fmessage,
+		build_string ("%d GCs, avg live/zombies = %.2f/%.2f"
+			      " (%f%%), max %d/%d\nzombies: %S"),
+		make_number (ngcs), make_float (avg_live),
+		make_float (avg_zombies),
+		make_float (avg_zombies / avg_live / 100),
+		make_number (max_live), make_number (max_zombies),
+		zombie_list);
 }
 
 #endif /* GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES */
@@ -5301,10 +5299,8 @@ purecopy (Lisp_Object obj)
     }
   else
     {
-      Lisp_Object args[2];
-      args[0] = build_pure_c_string ("Don't know how to purify: %S");
-      args[1] = obj;
-      Fsignal (Qerror, (Fcons (Fformat (2, args), Qnil)));
+      Lisp_Object fmt = build_pure_c_string ("Don't know how to purify: %S");
+      Fsignal (Qerror, list1 (CALLN (Fformat, fmt, obj)));
     }
 
   if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing.  */
@@ -5682,56 +5678,44 @@ garbage_collect_1 (void *end)
     }
 
   unbind_to (count, Qnil);
-  {
-    Lisp_Object total[11];
-    int total_size = 10;
-
-    total[0] = list4 (Qconses, make_number (sizeof (struct Lisp_Cons)),
-		      bounded_number (total_conses),
-		      bounded_number (total_free_conses));
-
-    total[1] = list4 (Qsymbols, make_number (sizeof (struct Lisp_Symbol)),
-		      bounded_number (total_symbols),
-		      bounded_number (total_free_symbols));
-
-    total[2] = list4 (Qmiscs, make_number (sizeof (union Lisp_Misc)),
-		      bounded_number (total_markers),
-		      bounded_number (total_free_markers));
-
-    total[3] = list4 (Qstrings, make_number (sizeof (struct Lisp_String)),
-		      bounded_number (total_strings),
-		      bounded_number (total_free_strings));
-
-    total[4] = list3 (Qstring_bytes, make_number (1),
-		      bounded_number (total_string_bytes));
 
-    total[5] = list3 (Qvectors,
-		      make_number (header_size + sizeof (Lisp_Object)),
-		      bounded_number (total_vectors));
-
-    total[6] = list4 (Qvector_slots, make_number (word_size),
-		      bounded_number (total_vector_slots),
-		      bounded_number (total_free_vector_slots));
-
-    total[7] = list4 (Qfloats, make_number (sizeof (struct Lisp_Float)),
-		      bounded_number (total_floats),
-		      bounded_number (total_free_floats));
-
-    total[8] = list4 (Qintervals, make_number (sizeof (struct interval)),
-		      bounded_number (total_intervals),
-		      bounded_number (total_free_intervals));
-
-    total[9] = list3 (Qbuffers, make_number (sizeof (struct buffer)),
-		      bounded_number (total_buffers));
+  Lisp_Object total[] = {
+    list4 (Qconses, make_number (sizeof (struct Lisp_Cons)),
+	   bounded_number (total_conses),
+	   bounded_number (total_free_conses)),
+    list4 (Qsymbols, make_number (sizeof (struct Lisp_Symbol)),
+	   bounded_number (total_symbols),
+	   bounded_number (total_free_symbols)),
+    list4 (Qmiscs, make_number (sizeof (union Lisp_Misc)),
+	   bounded_number (total_markers),
+	   bounded_number (total_free_markers)),
+    list4 (Qstrings, make_number (sizeof (struct Lisp_String)),
+	   bounded_number (total_strings),
+	   bounded_number (total_free_strings)),
+    list3 (Qstring_bytes, make_number (1),
+	   bounded_number (total_string_bytes)),
+    list3 (Qvectors,
+	   make_number (header_size + sizeof (Lisp_Object)),
+	   bounded_number (total_vectors)),
+    list4 (Qvector_slots, make_number (word_size),
+	   bounded_number (total_vector_slots),
+	   bounded_number (total_free_vector_slots)),
+    list4 (Qfloats, make_number (sizeof (struct Lisp_Float)),
+	   bounded_number (total_floats),
+	   bounded_number (total_free_floats)),
+    list4 (Qintervals, make_number (sizeof (struct interval)),
+	   bounded_number (total_intervals),
+	   bounded_number (total_free_intervals)),
+    list3 (Qbuffers, make_number (sizeof (struct buffer)),
+	   bounded_number (total_buffers)),
 
 #ifdef DOUG_LEA_MALLOC
-    total_size++;
-    total[10] = list4 (Qheap, make_number (1024),
-                       bounded_number ((mallinfo ().uordblks + 1023) >> 10),
-                       bounded_number ((mallinfo ().fordblks + 1023) >> 10));
+    list4 (Qheap, make_number (1024),
+	   bounded_number ((mallinfo ().uordblks + 1023) >> 10),
+	   bounded_number ((mallinfo ().fordblks + 1023) >> 10)),
 #endif
-    retval = Flist (total_size, total);
-  }
+  };
+  retval = CALLMANY (Flist, total);
 
 #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
   {
diff --git a/src/buffer.c b/src/buffer.c
index d0ffe67d9..67eda3e 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -387,7 +387,6 @@ followed by the rest of the buffers.  */)
   if (FRAMEP (frame))
     {
       Lisp_Object framelist, prevlist, tail;
-      Lisp_Object args[3];
 
       framelist = Fcopy_sequence (XFRAME (frame)->buffer_list);
       prevlist = Fnreverse (Fcopy_sequence
@@ -408,10 +407,7 @@ followed by the rest of the buffers.  */)
 	  tail = XCDR (tail);
 	}
 
-      args[0] = framelist;
-      args[1] = general;
-      args[2] = prevlist;
-      return Fnconc (3, args);
+      return CALLN (Fnconc, framelist, general, prevlist);
     }
   else
     return general;
@@ -1654,15 +1650,14 @@ cleaning up all windows currently displaying the buffer to be killed. */)
   /* Run hooks with the buffer to be killed the current buffer.  */
   {
     ptrdiff_t count = SPECPDL_INDEX ();
-    Lisp_Object arglist[1];
 
     record_unwind_protect (save_excursion_restore, save_excursion_save ());
     set_buffer_internal (b);
 
     /* First run the query functions; if any query is answered no,
        don't kill the buffer.  */
-    arglist[0] = Qkill_buffer_query_functions;
-    tem = Frun_hook_with_args_until_failure (1, arglist);
+    tem = CALLN (Frun_hook_with_args_until_failure,
+		 Qkill_buffer_query_functions);
     if (NILP (tem))
       return unbind_to (count, Qnil);
 
diff --git a/src/callint.c b/src/callint.c
index 43566ac..56cbcc1 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -229,17 +229,10 @@ read_file_name (Lisp_Object default_filename, Lisp_Object mustmatch,
 		Lisp_Object initial, Lisp_Object predicate)
 {
   struct gcpro gcpro1;
-  Lisp_Object args[7];
-
   GCPRO1 (default_filename);
-  args[0] = intern ("read-file-name");
-  args[1] = callint_message;
-  args[2] = Qnil;
-  args[3] = default_filename;
-  args[4] = mustmatch;
-  args[5] = initial;
-  args[6] = predicate;
-  RETURN_UNGCPRO (Ffuncall (7, args));
+  RETURN_UNGCPRO (CALLN (Ffuncall, intern ("read-file-name"),
+			 callint_message, Qnil, default_filename,
+			 mustmatch, initial, predicate));
 }
 
 /* BEWARE: Calling this directly from C would defeat the purpose!  */
@@ -397,15 +390,11 @@ invoke it.  If KEYS is omitted or nil, the return value of
       Vreal_this_command = save_real_this_command;
       kset_last_command (current_kboard, save_last_command);
 
-      {
-	Lisp_Object args[3];
-	args[0] = Qfuncall_interactively;
-	args[1] = function;
-	args[2] = specs;
-	Lisp_Object result = unbind_to (speccount, Fapply (3, args));
-	SAFE_FREE ();
-	return result;
-      }
+      Lisp_Object result
+	= unbind_to (speccount, CALLN (Fapply, Qfuncall_interactively,
+				       function, specs));
+      SAFE_FREE ();
+      return result;
     }
 
   /* SPECS is set to a string; use it as an interactive prompt.
diff --git a/src/charset.c b/src/charset.c
index ea1480e..9080840 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -2146,7 +2146,7 @@ DEFUN ("set-charset-priority", Fset_charset_priority, Sset_charset_priority,
 usage: (set-charset-priority &rest charsets)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
-  Lisp_Object new_head, old_list, arglist[2];
+  Lisp_Object new_head, old_list;
   Lisp_Object list_2022, list_emacs_mule;
   ptrdiff_t i;
   int id;
@@ -2162,9 +2162,9 @@ usage: (set-charset-priority &rest charsets)  */)
 	  new_head = Fcons (make_number (id), new_head);
 	}
     }
-  arglist[0] = Fnreverse (new_head);
-  arglist[1] = Vcharset_non_preferred_head = old_list;
-  Vcharset_ordered_list = Fnconc (2, arglist);
+  Vcharset_non_preferred_head = old_list;
+  Vcharset_ordered_list = CALLN (Fnconc, Fnreverse (new_head), old_list);
+
   charset_ordered_list_tick++;
 
   charset_unibyte = -1;
@@ -2353,12 +2353,7 @@ syms_of_charset (void)
   Vemacs_mule_charset_list = Qnil;
 
   staticpro (&Vcharset_hash_table);
-  {
-    Lisp_Object args[2];
-    args[0] = QCtest;
-    args[1] = Qeq;
-    Vcharset_hash_table = Fmake_hash_table (2, args);
-  }
+  Vcharset_hash_table = CALLN (Fmake_hash_table, QCtest, Qeq);
 
   charset_table = charset_table_init;
   charset_table_size = ARRAYELTS (charset_table_init);
diff --git a/src/chartab.c b/src/chartab.c
index 013a5be..acaabce 100644
--- a/src/chartab.c
+++ b/src/chartab.c
@@ -1255,8 +1255,10 @@ uniprop_encode_value_numeric (Lisp_Object table, Lisp_Object value)
       break;
   value = make_number (i);
   if (i == size)
-    set_char_table_extras (table, 4, Fvconcat (2, ((Lisp_Object []) {
-      XCHAR_TABLE (table)->extras[4], Fmake_vector (make_number (1), value) })));
+    set_char_table_extras (table, 4,
+			   CALLN (Fvconcat,
+				  XCHAR_TABLE (table)->extras[4],
+				  Fmake_vector (make_number (1), value)));
   return make_number (i);
 }
 
diff --git a/src/coding.c b/src/coding.c
index b95c0a5..3a3d0c9 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -10776,12 +10776,7 @@ void
 syms_of_coding (void)
 {
   staticpro (&Vcoding_system_hash_table);
-  {
-    Lisp_Object args[2];
-    args[0] = QCtest;
-    args[1] = Qeq;
-    Vcoding_system_hash_table = Fmake_hash_table (2, args);
-  }
+  Vcoding_system_hash_table = CALLN (Fmake_hash_table, QCtest, Qeq);
 
   staticpro (&Vsjis_coding_system);
   Vsjis_coding_system = Qnil;
@@ -11269,60 +11264,59 @@ See also `keyboard-translate-table'.
 Use of this variable for character code unification was rendered
 obsolete in Emacs 23.1 and later, since Unicode is now the basis of
 internal character representation.  */);
-    Vtranslation_table_for_input = Qnil;
-
-  {
-    Lisp_Object args[coding_arg_undecided_max];
-    memsetnil (args, ARRAYELTS (args));
-
-    Lisp_Object plist[16];
-    plist[0] = intern_c_string (":name");
-    plist[1] = args[coding_arg_name] = Qno_conversion;
-    plist[2] = intern_c_string (":mnemonic");
-    plist[3] = args[coding_arg_mnemonic] = make_number ('=');
-    plist[4] = intern_c_string (":coding-type");
-    plist[5] = args[coding_arg_coding_type] = Qraw_text;
-    plist[6] = intern_c_string (":ascii-compatible-p");
-    plist[7] = args[coding_arg_ascii_compatible_p] = Qt;
-    plist[8] = intern_c_string (":default-char");
-    plist[9] = args[coding_arg_default_char] = make_number (0);
-    plist[10] = intern_c_string (":for-unibyte");
-    plist[11] = args[coding_arg_for_unibyte] = Qt;
-    plist[12] = intern_c_string (":docstring");
-    plist[13] = build_pure_c_string ("Do no conversion.\n\
-\n\
-When you visit a file with this coding, the file is read into a\n\
-unibyte buffer as is, thus each byte of a file is treated as a\n\
-character.");
-    plist[14] = intern_c_string (":eol-type");
-    plist[15] = args[coding_arg_eol_type] = Qunix;
-    args[coding_arg_plist] = Flist (16, plist);
-    Fdefine_coding_system_internal (coding_arg_max, args);
-
-    plist[1] = args[coding_arg_name] = Qundecided;
-    plist[3] = args[coding_arg_mnemonic] = make_number ('-');
-    plist[5] = args[coding_arg_coding_type] = Qundecided;
-    /* This is already set.
-       plist[7] = args[coding_arg_ascii_compatible_p] = Qt; */
-    plist[8] = intern_c_string (":charset-list");
-    plist[9] = args[coding_arg_charset_list] = Fcons (Qascii, Qnil);
-    plist[11] = args[coding_arg_for_unibyte] = Qnil;
-    plist[13] = build_pure_c_string ("No conversion on encoding, automatic conversion on decoding.");
-    plist[15] = args[coding_arg_eol_type] = Qnil;
-    args[coding_arg_plist] = Flist (16, plist);
-    args[coding_arg_undecided_inhibit_null_byte_detection] = make_number (0);
-    args[coding_arg_undecided_inhibit_iso_escape_detection] = make_number (0);
-    Fdefine_coding_system_internal (coding_arg_undecided_max, args);
-  }
+  Vtranslation_table_for_input = Qnil;
+
+  Lisp_Object args[coding_arg_undecided_max];
+  memsetnil (args, ARRAYELTS (args));
+
+  Lisp_Object plist[] =
+    {
+      intern_c_string (":name"),
+      args[coding_arg_name] = Qno_conversion,
+      intern_c_string (":mnemonic"),
+      args[coding_arg_mnemonic] = make_number ('='),
+      intern_c_string (":coding-type"),
+      args[coding_arg_coding_type] = Qraw_text,
+      intern_c_string (":ascii-compatible-p"),
+      args[coding_arg_ascii_compatible_p] = Qt,
+      intern_c_string (":default-char"),
+      args[coding_arg_default_char] = make_number (0),
+      intern_c_string (":for-unibyte"),
+      args[coding_arg_for_unibyte] = Qt,
+      intern_c_string (":docstring"),
+      (build_pure_c_string
+       ("Do no conversion.\n"
+	"\n"
+	"When you visit a file with this coding, the file is read into a\n"
+	"unibyte buffer as is, thus each byte of a file is treated as a\n"
+	"character.")),
+      intern_c_string (":eol-type"),
+      args[coding_arg_eol_type] = Qunix,
+    };
+  args[coding_arg_plist] = CALLMANY (Flist, plist);
+  Fdefine_coding_system_internal (coding_arg_max, args);
+
+  plist[1] = args[coding_arg_name] = Qundecided;
+  plist[3] = args[coding_arg_mnemonic] = make_number ('-');
+  plist[5] = args[coding_arg_coding_type] = Qundecided;
+  /* This is already set.
+     plist[7] = args[coding_arg_ascii_compatible_p] = Qt; */
+  plist[8] = intern_c_string (":charset-list");
+  plist[9] = args[coding_arg_charset_list] = Fcons (Qascii, Qnil);
+  plist[11] = args[coding_arg_for_unibyte] = Qnil;
+  plist[13] = build_pure_c_string ("No conversion on encoding, "
+				   "automatic conversion on decoding.");
+  plist[15] = args[coding_arg_eol_type] = Qnil;
+  args[coding_arg_plist] = CALLMANY (Flist, plist);
+  args[coding_arg_undecided_inhibit_null_byte_detection] = make_number (0);
+  args[coding_arg_undecided_inhibit_iso_escape_detection] = make_number (0);
+  Fdefine_coding_system_internal (coding_arg_undecided_max, args);
 
   setup_coding_system (Qno_conversion, &safe_terminal_coding);
 
-  {
-    int i;
+  for (int i = 0; i < coding_category_max; i++)
+    Fset (AREF (Vcoding_category_table, i), Qno_conversion);
 
-    for (i = 0; i < coding_category_max; i++)
-      Fset (AREF (Vcoding_category_table, i), Qno_conversion);
-  }
 #if defined (DOS_NT)
   system_eol_type = Qdos;
 #else
diff --git a/src/composite.c b/src/composite.c
index 8ac5ef7..577b979 100644
--- a/src/composite.c
+++ b/src/composite.c
@@ -1891,36 +1891,18 @@ syms_of_composite (void)
   DEFSYM (Qcomposition, "composition");
 
   /* Make a hash table for static composition.  */
-  {
-    Lisp_Object args[6];
-
-    args[0] = QCtest;
-    args[1] = Qequal;
-    args[2] = QCweakness;
-    /* We used to make the hash table weak so that unreferenced
-       compositions can be garbage-collected.  But, usually once
-       created compositions are repeatedly used in an Emacs session,
-       and thus it's not worth to save memory in such a way.  So, we
-       make the table not weak.  */
-    args[3] = Qnil;
-    args[4] = QCsize;
-    args[5] = make_number (311);
-    composition_hash_table = Fmake_hash_table (6, args);
-    staticpro (&composition_hash_table);
-  }
+  /* We used to make the hash table weak so that unreferenced
+     compositions can be garbage-collected.  But, usually once
+     created compositions are repeatedly used in an Emacs session,
+     and thus it's not worth to save memory in such a way.  So, we
+     make the table not weak.  */
+  Lisp_Object args[] = {QCtest, Qequal, QCsize, make_number (311)};
+  composition_hash_table = CALLMANY (Fmake_hash_table, args);
+  staticpro (&composition_hash_table);
 
   /* Make a hash table for glyph-string.  */
-  {
-    Lisp_Object args[6];
-    args[0] = QCtest;
-    args[1] = Qequal;
-    args[2] = QCweakness;
-    args[3] = Qnil;
-    args[4] = QCsize;
-    args[5] = make_number (311);
-    gstring_hash_table = Fmake_hash_table (6, args);
-    staticpro (&gstring_hash_table);
-  }
+  gstring_hash_table = CALLMANY (Fmake_hash_table, args);
+  staticpro (&gstring_hash_table);
 
   staticpro (&gstring_work_headers);
   gstring_work_headers = make_uninit_vector (8);
diff --git a/src/data.c b/src/data.c
index 0389eb4..d06b991 100644
--- a/src/data.c
+++ b/src/data.c
@@ -972,9 +972,8 @@ wrong_range (Lisp_Object min, Lisp_Object max, Lisp_Object wrong)
   AUTO_STRING (value_should_be_from, "Value should be from ");
   AUTO_STRING (to, " to ");
   xsignal2 (Qerror,
-	    Fconcat (4, ((Lisp_Object [])
-			 {value_should_be_from, Fnumber_to_string (min),
-			  to, Fnumber_to_string (max)})),
+	    CALLN (Fconcat, value_should_be_from, Fnumber_to_string (min),
+		   to, Fnumber_to_string (max)),
 	    wrong);
 }
 
diff --git a/src/dbusbind.c b/src/dbusbind.c
index 3bdec0f..54e92cc 100644
--- a/src/dbusbind.c
+++ b/src/dbusbind.c
@@ -1849,12 +1849,7 @@ string denoting the bus address.  SERIAL is the serial number of the
 non-blocking method call, a reply is expected.  Both arguments must
 not be nil.  The value in the hash table is HANDLER, the function to
 be called when the D-Bus reply message arrives.  */);
-  {
-    Lisp_Object args[2];
-    args[0] = QCtest;
-    args[1] = Qequal;
-    Vdbus_registered_objects_table = Fmake_hash_table (2, args);
-  }
+  Vdbus_registered_objects_table = CALLN (Fmake_hash_table, QCtest, Qequal);
 
   DEFVAR_LISP ("dbus-debug", Vdbus_debug,
     doc: /* If non-nil, debug messages of D-Bus bindings are raised.  */);
diff --git a/src/dired.c b/src/dired.c
index ca43cd9..e31fdf8 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -914,7 +914,6 @@ so last access time will always be midnight of that day.  */)
 static Lisp_Object
 file_attributes (int fd, char const *name, Lisp_Object id_format)
 {
-  Lisp_Object values[12];
   struct stat s;
   int lstat_result;
 
@@ -941,10 +940,6 @@ file_attributes (int fd, char const *name, Lisp_Object id_format)
   if (lstat_result < 0)
     return Qnil;
 
-  values[0] = (S_ISLNK (s.st_mode) ? emacs_readlinkat (fd, name)
-	       : S_ISDIR (s.st_mode) ? Qt : Qnil);
-  values[1] = make_number (s.st_nlink);
-
   if (!(NILP (id_format) || EQ (id_format, Qinteger)))
     {
       block_input ();
@@ -952,34 +947,35 @@ file_attributes (int fd, char const *name, Lisp_Object id_format)
       gname = stat_gname (&s);
       unblock_input ();
     }
-  if (uname)
-    values[2] = DECODE_SYSTEM (build_unibyte_string (uname));
-  else
-    values[2] = make_fixnum_or_float (s.st_uid);
-  if (gname)
-    values[3] = DECODE_SYSTEM (build_unibyte_string (gname));
-  else
-    values[3] = make_fixnum_or_float (s.st_gid);
-
-  values[4] = make_lisp_time (get_stat_atime (&s));
-  values[5] = make_lisp_time (get_stat_mtime (&s));
-  values[6] = make_lisp_time (get_stat_ctime (&s));
-
-  /* If the file size is a 4-byte type, assume that files of sizes in
-     the 2-4 GiB range wrap around to negative values, as this is a
-     common bug on older 32-bit platforms.  */
-  if (sizeof (s.st_size) == 4)
-    values[7] = make_fixnum_or_float (s.st_size & 0xffffffffu);
-  else
-    values[7] = make_fixnum_or_float (s.st_size);
 
   filemodestring (&s, modes);
-  values[8] = make_string (modes, 10);
-  values[9] = Qt;
-  values[10] = INTEGER_TO_CONS (s.st_ino);
-  values[11] = INTEGER_TO_CONS (s.st_dev);
 
-  return Flist (ARRAYELTS (values), values);
+  return CALLN (Flist,
+		(S_ISLNK (s.st_mode) ? emacs_readlinkat (fd, name)
+		 : S_ISDIR (s.st_mode) ? Qt : Qnil),
+		make_number (s.st_nlink),
+		(uname
+		 ? DECODE_SYSTEM (build_unibyte_string (uname))
+		 : make_fixnum_or_float (s.st_uid)),
+		(gname
+		 ? DECODE_SYSTEM (build_unibyte_string (gname))
+		 : make_fixnum_or_float (s.st_gid)),
+		make_lisp_time (get_stat_atime (&s)),
+		make_lisp_time (get_stat_mtime (&s)),
+		make_lisp_time (get_stat_ctime (&s)),
+
+		/* If the file size is a 4-byte type, assume that
+		   files of sizes in the 2-4 GiB range wrap around to
+		   negative values, as this is a common bug on older
+		   32-bit platforms.  */
+		make_fixnum_or_float (sizeof (s.st_size) == 4
+				      ? s.st_size & 0xffffffffu
+				      : s.st_size),
+
+		make_string (modes, 10),
+		Qt,
+		INTEGER_TO_CONS (s.st_ino),
+		INTEGER_TO_CONS (s.st_dev));
 }
 
 DEFUN ("file-attributes-lessp", Ffile_attributes_lessp, Sfile_attributes_lessp, 2, 2, 0,
diff --git a/src/doc.c b/src/doc.c
index a6ef84b..8b18fb0 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -299,19 +299,6 @@ read_doc_string (Lisp_Object filepos)
 static bool
 reread_doc_file (Lisp_Object file)
 {
-#if 0
-  Lisp_Object reply, prompt[3];
-  struct gcpro gcpro1;
-  GCPRO1 (file);
-  prompt[0] = build_string ("File ");
-  prompt[1] = NILP (file) ? Vdoc_file_name : file;
-  prompt[2] = build_string (" is out of sync.  Reload? ");
-  reply = Fy_or_n_p (Fconcat (3, prompt));
-  UNGCPRO;
-  if (NILP (reply))
-    return 0;
-#endif
-
   if (NILP (file))
     Fsnarf_documentation (Vdoc_file_name);
   else
diff --git a/src/editfns.c b/src/editfns.c
index 621e841..7026ccc 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -2033,20 +2033,20 @@ DOW and ZONE.)  */)
   /* Avoid overflow when INT_MAX < EMACS_INT_MAX.  */
   EMACS_INT tm_year_base = TM_YEAR_BASE;
 
-  return Flist (9, ((Lisp_Object [])
-		    {make_number (local_tm.tm_sec),
-		     make_number (local_tm.tm_min),
-		     make_number (local_tm.tm_hour),
-		     make_number (local_tm.tm_mday),
-		     make_number (local_tm.tm_mon + 1),
-		     make_number (local_tm.tm_year + tm_year_base),
-		     make_number (local_tm.tm_wday),
-		     local_tm.tm_isdst ? Qt : Qnil,
-		     (HAVE_TM_GMTOFF
-		      ? make_number (tm_gmtoff (&local_tm))
-		      : gmtime_r (&time_spec, &gmt_tm)
-		      ? make_number (tm_diff (&local_tm, &gmt_tm))
-		      : Qnil)}));
+  return CALLN (Flist,
+		make_number (local_tm.tm_sec),
+		make_number (local_tm.tm_min),
+		make_number (local_tm.tm_hour),
+		make_number (local_tm.tm_mday),
+		make_number (local_tm.tm_mon + 1),
+		make_number (local_tm.tm_year + tm_year_base),
+		make_number (local_tm.tm_wday),
+		local_tm.tm_isdst ? Qt : Qnil,
+		(HAVE_TM_GMTOFF
+		 ? make_number (tm_gmtoff (&local_tm))
+		 : gmtime_r (&time_spec, &gmt_tm)
+		 ? make_number (tm_diff (&local_tm, &gmt_tm))
+		 : Qnil));
 }
 
 /* Return OBJ - OFFSET, checking that OBJ is a valid fixnum and that
@@ -2679,25 +2679,20 @@ update_buffer_properties (ptrdiff_t start, ptrdiff_t end)
      call them, specifying the range of the buffer being accessed.  */
   if (!NILP (Vbuffer_access_fontify_functions))
     {
-      Lisp_Object args[3];
-      Lisp_Object tem;
-
-      args[0] = Qbuffer_access_fontify_functions;
-      XSETINT (args[1], start);
-      XSETINT (args[2], end);
-
       /* But don't call them if we can tell that the work
 	 has already been done.  */
       if (!NILP (Vbuffer_access_fontified_property))
 	{
-	  tem = Ftext_property_any (args[1], args[2],
-				    Vbuffer_access_fontified_property,
-				    Qnil, Qnil);
-	  if (! NILP (tem))
-	    Frun_hook_with_args (3, args);
+	  Lisp_Object tem
+	    = Ftext_property_any (make_number (start), make_number (end),
+				  Vbuffer_access_fontified_property,
+				  Qnil, Qnil);
+	  if (NILP (tem))
+	    return;
 	}
-      else
-	Frun_hook_with_args (3, args);
+
+      CALLN (Frun_hook_with_args, Qbuffer_access_fontify_functions,
+	     make_number (start), make_number (end));
     }
 }
 
@@ -4516,7 +4511,7 @@ Lisp_Object
 format2 (const char *string1, Lisp_Object arg0, Lisp_Object arg1)
 {
   AUTO_STRING (format, string1);
-  return Fformat (3, (Lisp_Object []) {format, arg0, arg1});
+  return CALLN (Fformat, format, arg0, arg1);
 }
 
 DEFUN ("char-equal", Fchar_equal, Schar_equal, 2, 2, 0,
diff --git a/src/eval.c b/src/eval.c
index ddf6535..e7e0a06 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2534,15 +2534,14 @@ run_hook (Lisp_Object hook)
 void
 run_hook_with_args_2 (Lisp_Object hook, Lisp_Object arg1, Lisp_Object arg2)
 {
-  Frun_hook_with_args (3, ((Lisp_Object []) { hook, arg1, arg2 }));
+  CALLN (Frun_hook_with_args, hook, arg1, arg2);
 }
 
 /* Apply fn to arg.  */
 Lisp_Object
 apply1 (Lisp_Object fn, Lisp_Object arg)
 {
-  return (NILP (arg) ? Ffuncall (1, &fn)
-	  : Fapply (2, ((Lisp_Object []) { fn, arg })));
+  return NILP (arg) ? Ffuncall (1, &fn) : CALLN (Fapply, fn, arg);
 }
 
 /* Call function fn on no arguments.  */
@@ -2557,7 +2556,7 @@ call0 (Lisp_Object fn)
 Lisp_Object
 call1 (Lisp_Object fn, Lisp_Object arg1)
 {
-  return Ffuncall (2, ((Lisp_Object []) { fn, arg1 }));
+  return CALLN (Ffuncall, fn, arg1);
 }
 
 /* Call function fn with 2 arguments arg1, arg2.  */
@@ -2565,7 +2564,7 @@ call1 (Lisp_Object fn, Lisp_Object arg1)
 Lisp_Object
 call2 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2)
 {
-  return Ffuncall (3, ((Lisp_Object []) { fn, arg1, arg2 }));
+  return CALLN (Ffuncall, fn, arg1, arg2);
 }
 
 /* Call function fn with 3 arguments arg1, arg2, arg3.  */
@@ -2573,7 +2572,7 @@ call2 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2)
 Lisp_Object
 call3 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3)
 {
-  return Ffuncall (4, ((Lisp_Object []) { fn, arg1, arg2, arg3 }));
+  return CALLN (Ffuncall, fn, arg1, arg2, arg3);
 }
 
 /* Call function fn with 4 arguments arg1, arg2, arg3, arg4.  */
@@ -2582,7 +2581,7 @@ Lisp_Object
 call4 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
        Lisp_Object arg4)
 {
-  return Ffuncall (5, ((Lisp_Object []) { fn, arg1, arg2, arg3, arg4 }));
+  return CALLN (Ffuncall, fn, arg1, arg2, arg3, arg4);
 }
 
 /* Call function fn with 5 arguments arg1, arg2, arg3, arg4, arg5.  */
@@ -2591,7 +2590,7 @@ Lisp_Object
 call5 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
        Lisp_Object arg4, Lisp_Object arg5)
 {
-  return Ffuncall (6, ((Lisp_Object []) { fn, arg1, arg2, arg3, arg4, arg5 }));
+  return CALLN (Ffuncall, fn, arg1, arg2, arg3, arg4, arg5);
 }
 
 /* Call function fn with 6 arguments arg1, arg2, arg3, arg4, arg5, arg6.  */
@@ -2600,8 +2599,7 @@ Lisp_Object
 call6 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
        Lisp_Object arg4, Lisp_Object arg5, Lisp_Object arg6)
 {
-  return Ffuncall (7, ((Lisp_Object [])
-    { fn, arg1, arg2, arg3, arg4, arg5, arg6 }));
+  return CALLN (Ffuncall, fn, arg1, arg2, arg3, arg4, arg5, arg6);
 }
 
 /* Call function fn with 7 arguments arg1, arg2, arg3, arg4, arg5, arg6, arg7.  */
@@ -2610,8 +2608,7 @@ Lisp_Object
 call7 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3,
        Lisp_Object arg4, Lisp_Object arg5, Lisp_Object arg6, Lisp_Object arg7)
 {
-  return Ffuncall (8, ((Lisp_Object [])
-    { fn, arg1, arg2, arg3, arg4, arg5, arg6, arg7 }));
+  return CALLN (Ffuncall, fn, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
 }
 
 /* The caller should GCPRO all the elements of ARGS.  */
diff --git a/src/fileio.c b/src/fileio.c
index ff6720d..e467ec1 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -3670,11 +3670,9 @@ by calling `format-decode', which see.  */)
 	    {
 	      /* If we have not yet decided a coding system, check
                  file-coding-system-alist.  */
-	      Lisp_Object args[6];
-
-	      args[0] = Qinsert_file_contents, args[1] = orig_filename;
-	      args[2] = visit, args[3] = beg, args[4] = end, args[5] = replace;
-	      coding_system = Ffind_operation_coding_system (6, args);
+	      coding_system = CALLN (Ffind_operation_coding_system,
+				     Qinsert_file_contents, orig_filename,
+				     visit, beg, end, replace);
 	      if (CONSP (coding_system))
 		coding_system = XCAR (coding_system);
 	    }
@@ -4251,11 +4249,9 @@ by calling `format-decode', which see.  */)
 	    {
 	      /* If the coding system is not yet decided, check
 		 file-coding-system-alist.  */
-	      Lisp_Object args[6];
-
-	      args[0] = Qinsert_file_contents, args[1] = orig_filename;
-	      args[2] = visit, args[3] = beg, args[4] = end, args[5] = Qnil;
-	      coding_system = Ffind_operation_coding_system (6, args);
+	      coding_system = CALLN (Ffind_operation_coding_system,
+				     Qinsert_file_contents, orig_filename,
+				     visit, beg, end, Qnil);
 	      if (CONSP (coding_system))
 		coding_system = XCAR (coding_system);
 	    }
@@ -4583,12 +4579,9 @@ choose_write_coding_system (Lisp_Object start, Lisp_Object end, Lisp_Object file
       if (NILP (val))
 	{
 	  /* Check file-coding-system-alist.  */
-	  Lisp_Object args[7], coding_systems;
-
-	  args[0] = Qwrite_region; args[1] = start; args[2] = end;
-	  args[3] = filename; args[4] = append; args[5] = visit;
-	  args[6] = lockname;
-	  coding_systems = Ffind_operation_coding_system (7, args);
+	  Lisp_Object coding_systems
+	    = CALLN (Ffind_operation_coding_system, Qwrite_region, start, end,
+		     filename, append, visit, lockname);
 	  if (CONSP (coding_systems) && !NILP (XCDR (coding_systems)))
 	    val = XCDR (coding_systems);
 	}
@@ -5041,10 +5034,7 @@ DEFUN ("car-less-than-car", Fcar_less_than_car, Scar_less_than_car, 2, 2, 0,
        doc: /* Return t if (car A) is numerically less than (car B).  */)
   (Lisp_Object a, Lisp_Object b)
 {
-  Lisp_Object args[2];
-  args[0] = Fcar (a);
-  args[1] = Fcar (b);
-  return Flss (2, args);
+  return CALLN (Flss, Fcar (a), Fcar (b));
 }
 
 /* Build the complete list of annotations appropriate for writing out
@@ -5063,7 +5053,7 @@ build_annotations (Lisp_Object start, Lisp_Object end)
   struct gcpro gcpro1, gcpro2;
   Lisp_Object original_buffer;
   int i;
-  bool used_global = 0;
+  bool used_global = false;
 
   XSETBUFFER (original_buffer, current_buffer);
 
@@ -5075,11 +5065,10 @@ build_annotations (Lisp_Object start, Lisp_Object end)
       struct buffer *given_buffer = current_buffer;
       if (EQ (Qt, XCAR (p)) && !used_global)
 	{ /* Use the global value of the hook.  */
-	  Lisp_Object arg[2];
-	  used_global = 1;
-	  arg[0] = Fdefault_value (Qwrite_region_annotate_functions);
-	  arg[1] = XCDR (p);
-	  p = Fappend (2, arg);
+	  used_global = true;
+	  p = CALLN (Fappend,
+		     Fdefault_value (Qwrite_region_annotate_functions),
+		     XCDR (p));
 	  continue;
 	}
       Vwrite_region_annotations_so_far = annotations;
@@ -5408,9 +5397,8 @@ auto_save_error (Lisp_Object error_val)
   ring_bell (XFRAME (selected_frame));
 
   AUTO_STRING (format, "Auto-saving %s: %s");
-  msg = Fformat (3, ((Lisp_Object [])
-		     {format, BVAR (current_buffer, name),
-		      Ferror_message_string (error_val)}));
+  msg = CALLN (Fformat, format, BVAR (current_buffer, name),
+	       Ferror_message_string (error_val));
   GCPRO1 (msg);
 
   for (i = 0; i < 3; ++i)
diff --git a/src/filelock.c b/src/filelock.c
index 8e88435..89d3e35 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -209,8 +209,6 @@ get_boot_time (void)
 					    WTMP_FILE, counter);
 	  if (! NILP (Ffile_exists_p (tempname)))
 	    {
-	      Lisp_Object args[6];
-
 	      /* The utmp functions on mescaline.gnu.org accept only
 		 file names up to 8 characters long.  Choose a 2
 		 character long prefix, and call make_temp_file with
@@ -219,13 +217,9 @@ get_boot_time (void)
 	      filename = Fexpand_file_name (build_string ("wt"),
 					    Vtemporary_file_directory);
 	      filename = make_temp_name (filename, 1);
-	      args[0] = build_string ("gzip");
-	      args[1] = Qnil;
-	      args[2] = list2 (QCfile, filename);
-	      args[3] = Qnil;
-	      args[4] = build_string ("-cd");
-	      args[5] = tempname;
-	      Fcall_process (6, args);
+	      CALLN (Fcall_process, build_string ("gzip"), Qnil,
+		     list2 (QCfile, filename), Qnil,
+		     build_string ("-cd"), tempname);
 	      delete_flag = 1;
 	    }
 	}
diff --git a/src/fns.c b/src/fns.c
index d177294..3f79304 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -440,21 +440,14 @@ static Lisp_Object concat (ptrdiff_t nargs, Lisp_Object *args,
 Lisp_Object
 concat2 (Lisp_Object s1, Lisp_Object s2)
 {
-  Lisp_Object args[2];
-  args[0] = s1;
-  args[1] = s2;
-  return concat (2, args, Lisp_String, 0);
+  return concat (2, (Lisp_Object []) {s1, s2}, Lisp_String, 0);
 }
 
 /* ARGSUSED */
 Lisp_Object
 concat3 (Lisp_Object s1, Lisp_Object s2, Lisp_Object s3)
 {
-  Lisp_Object args[3];
-  args[0] = s1;
-  args[1] = s2;
-  args[2] = s3;
-  return concat (3, args, Lisp_String, 0);
+  return concat (3, (Lisp_Object []) {s1, s2, s3}, Lisp_String, 0);
 }
 
 DEFUN ("append", Fappend, Sappend, 0, MANY, 0,
@@ -2255,12 +2248,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props,
       if (depth > 200)
 	error ("Stack overflow in equal");
       if (NILP (ht))
-	{
-	  Lisp_Object args[2];
-	  args[0] = QCtest;
-	  args[1] = Qeq;
-	  ht = Fmake_hash_table (2, args);
-	}
+	ht = CALLN (Fmake_hash_table, QCtest, Qeq);
       switch (XTYPE (o1))
 	{
 	case Lisp_Cons: case Lisp_Misc: case Lisp_Vectorlike:
@@ -2464,10 +2452,7 @@ This makes STRING unibyte and may change its length.  */)
 Lisp_Object
 nconc2 (Lisp_Object s1, Lisp_Object s2)
 {
-  Lisp_Object args[2];
-  args[0] = s1;
-  args[1] = s2;
-  return Fnconc (2, args);
+  return CALLN (Fnconc, s1, s2);
 }
 
 DEFUN ("nconc", Fnconc, Snconc, 0, MANY, 0,
@@ -2715,7 +2700,7 @@ if `last-nonmenu-event' is nil, and `use-dialog-box' is non-nil.  */)
     }
 
   AUTO_STRING (yes_or_no, "(yes or no) ");
-  prompt = Fconcat (2, (Lisp_Object []) {prompt, yes_or_no});
+  prompt = CALLN (Fconcat, prompt, yes_or_no);
   GCPRO1 (prompt);
 
   while (1)
@@ -2995,15 +2980,13 @@ usage: (widget-apply WIDGET PROPERTY &rest ARGS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
   /* This function can GC.  */
-  Lisp_Object newargs[3];
   struct gcpro gcpro1, gcpro2;
-  Lisp_Object result;
-
-  newargs[0] = Fwidget_get (args[0], args[1]);
-  newargs[1] = args[0];
-  newargs[2] = Flist (nargs - 2, args + 2);
-  GCPRO2 (newargs[0], newargs[2]);
-  result = Fapply (3, newargs);
+  Lisp_Object widget = args[0];
+  Lisp_Object property = args[1];
+  Lisp_Object propval = Fwidget_get (widget, property);
+  Lisp_Object trailing_args = Flist (nargs - 2, args + 2);
+  GCPRO2 (propval, trailing_args);
+  Lisp_Object result = CALLN (Fapply, propval, widget, trailing_args);
   UNGCPRO;
   return result;
 }
@@ -3750,12 +3733,7 @@ cmpfn_user_defined (struct hash_table_test *ht,
 		    Lisp_Object key1,
 		    Lisp_Object key2)
 {
-  Lisp_Object args[3];
-
-  args[0] = ht->user_cmp_function;
-  args[1] = key1;
-  args[2] = key2;
-  return !NILP (Ffuncall (3, args));
+  return !NILP (call2 (ht->user_cmp_function, key1, key2));
 }

@@ -3803,11 +3781,7 @@ hashfn_equal (struct hash_table_test *ht, Lisp_Object key)
 static EMACS_UINT
 hashfn_user_defined (struct hash_table_test *ht, Lisp_Object key)
 {
-  Lisp_Object args[2], hash;
-
-  args[0] = ht->user_hash_function;
-  args[1] = key;
-  hash = Ffuncall (2, args);
+  Lisp_Object hash = call1 (ht->user_hash_function, key);
   return hashfn_eq (ht, hash);
 }
 
@@ -3980,9 +3954,8 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h)
 #ifdef ENABLE_CHECKING
       if (HASH_TABLE_P (Vpurify_flag)
 	  && XHASH_TABLE (Vpurify_flag) == h)
-	Fmessage (2, ((Lisp_Object [])
-	  { build_string ("Growing hash table to: %d"),
-	    make_number (new_size) }));
+	CALLN (Fmessage, build_string ("Growing hash table to: %d"),
+	       make_number (new_size));
 #endif
 
       set_hash_key_and_value (h, larger_vector (h->key_and_value,
@@ -4759,17 +4732,10 @@ FUNCTION is called with two arguments, KEY and VALUE.
   (Lisp_Object function, Lisp_Object table)
 {
   struct Lisp_Hash_Table *h = check_hash_table (table);
-  Lisp_Object args[3];
-  ptrdiff_t i;
 
-  for (i = 0; i < HASH_TABLE_SIZE (h); ++i)
+  for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i)
     if (!NILP (HASH_HASH (h, i)))
-      {
-	args[0] = function;
-	args[1] = HASH_KEY (h, i);
-	args[2] = HASH_VALUE (h, i);
-	Ffuncall (3, args);
-      }
+      call2 (function, HASH_KEY (h, i), HASH_VALUE (h, i));
 
   return Qnil;
 }
@@ -4911,11 +4877,9 @@ secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start,
 	      if (NILP (coding_system) && !NILP (Fbuffer_file_name (object)))
 		{
 		  /* Check file-coding-system-alist.  */
-		  Lisp_Object args[4], val;
-
-		  args[0] = Qwrite_region; args[1] = start; args[2] = end;
-		  args[3] = Fbuffer_file_name (object);
-		  val = Ffind_operation_coding_system (4, args);
+		  Lisp_Object val = CALLN (Ffind_operation_coding_system,
+					   Qwrite_region, start, end,
+					   Fbuffer_file_name (object));
 		  if (CONSP (val) && !NILP (XCDR (val)))
 		    coding_system = XCDR (val);
 		}
diff --git a/src/font.c b/src/font.c
index 190b33a..ebad8d0 100644
--- a/src/font.c
+++ b/src/font.c
@@ -374,8 +374,7 @@ font_style_to_value (enum font_property_index prop, Lisp_Object val,
       elt = Fmake_vector (make_number (2), make_number (100));
       ASET (elt, 1, val);
       ASET (font_style_table, prop - FONT_WEIGHT_INDEX,
-	    Fvconcat (2, ((Lisp_Object [])
-	      { table, Fmake_vector (make_number (1), elt) })));
+	    CALLN (Fvconcat, table, Fmake_vector (make_number (1), elt)));
       return (100 << 8) | (i << 4);
     }
   else
@@ -3400,16 +3399,11 @@ font_open_by_spec (struct frame *f, Lisp_Object spec)
 Lisp_Object
 font_open_by_name (struct frame *f, Lisp_Object name)
 {
-  Lisp_Object args[2];
-  Lisp_Object spec, ret;
-
-  args[0] = QCname;
-  args[1] = name;
-  spec = Ffont_spec (2, args);
-  ret = font_open_by_spec (f, spec);
+  Lisp_Object spec = CALLN (Ffont_spec, QCname, name);
+  Lisp_Object ret = font_open_by_spec (f, spec);
   /* Do not lose name originally put in.  */
   if (!NILP (ret))
-    font_put_extra (ret, QCuser_spec, args[1]);
+    font_put_extra (ret, QCuser_spec, name);
 
   return ret;
 }
@@ -4181,13 +4175,7 @@ how close they are to PREFER.  */)
   else
     vec = font_vconcat_entity_vectors (list);
   if (n == 0 || n >= ASIZE (vec))
-    {
-      Lisp_Object args[2];
-
-      args[0] = vec;
-      args[1] = Qnil;
-      list = Fappend (2, args);
-    }
+    list = CALLN (Fappend, vec, Qnil);
   else
     {
       for (list = Qnil, n--; n >= 0; n--)
diff --git a/src/fontset.c b/src/fontset.c
index b257da1..357526b 100644
--- a/src/fontset.c
+++ b/src/fontset.c
@@ -349,16 +349,17 @@ fontset_add (Lisp_Object fontset, Lisp_Object range, Lisp_Object elt, Lisp_Objec
 	from1 = from, to1 = to;
 	args[idx] = char_table_ref_and_range (fontset, from, &from1, &to1);
 	char_table_set_range (fontset, from, to1,
-			      NILP (args[idx]) ? args[1 - idx]
-			      : Fvconcat (2, args));
+			      (NILP (args[idx]) ? args[1 - idx]
+			       : CALLMANY (Fvconcat, args)));
 	from = to1 + 1;
       } while (from < to);
     }
   else
     {
       args[idx] = FONTSET_FALLBACK (fontset);
-      set_fontset_fallback
-	(fontset, NILP (args[idx]) ? args[1 - idx] : Fvconcat (2, args));
+      set_fontset_fallback (fontset,
+			    (NILP (args[idx]) ? args[1 - idx]
+			     : CALLMANY (Fvconcat, args)));
     }
 }
 
@@ -1432,12 +1433,8 @@ appended.  By default, FONT-SPEC overrides the previous settings.  */)
     }
   else if (STRINGP (font_spec))
     {
-      Lisp_Object args[2];
-
       fontname = font_spec;
-      args[0] = QCname;
-      args[1] = font_spec;
-      font_spec = Ffont_spec (2, args);
+      font_spec = CALLN (Ffont_spec, QCname, fontname);
     }
   else if (FONT_SPEC_P (font_spec))
     fontname = Ffont_xlfd_name (font_spec, Qnil);
diff --git a/src/ftfont.c b/src/ftfont.c
index 053b95f..adf1888 100644
--- a/src/ftfont.c
+++ b/src/ftfont.c
@@ -375,13 +375,7 @@ ftfont_lookup_cache (Lisp_Object key, enum ftfont_cache_for cache_for)
   if (NILP (cache))
     {
       if (NILP (ft_face_cache))
-	{
-	  Lisp_Object args[2];
-
-	  args[0] = QCtest;
-	  args[1] = Qequal;
-	  ft_face_cache = Fmake_hash_table (2, args);
-	}
+	ft_face_cache = CALLN (Fmake_hash_table, QCtest, Qequal);
       cache_data = xmalloc (sizeof *cache_data);
       cache_data->ft_face = NULL;
       cache_data->fc_charset = NULL;
diff --git a/src/gtkutil.c b/src/gtkutil.c
index da05742..21f3cb1 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -2072,28 +2072,17 @@ xg_get_font (struct frame *f, const char *default_name)
 
       if (desc)
 	{
-	  Lisp_Object args[10];
 	  const char *name   = pango_font_description_get_family (desc);
 	  gint        size   = pango_font_description_get_size (desc);
 	  PangoWeight weight = pango_font_description_get_weight (desc);
 	  PangoStyle  style  = pango_font_description_get_style (desc);
 
-	  args[0] = QCname;
-	  args[1] = build_string (name);
-
-	  args[2] = QCsize;
-	  args[3] = make_float (pango_units_to_double (size));
-
-	  args[4] = QCweight;
-	  args[5] = XG_WEIGHT_TO_SYMBOL (weight);
-
-	  args[6] = QCslant;
-	  args[7] = XG_STYLE_TO_SYMBOL (style);
-
-	  args[8] = QCtype;
-	  args[9] = Qxft;
-
-	  font = Ffont_spec (10, args);
+	  font = CALLN (Ffont_spec,
+			QCname, build_string (name),
+			QCsize, make_float (pango_units_to_double (size)),
+			QCweight, XG_WEIGHT_TO_SYMBOL (weight),
+			QCslant, XG_STYLE_TO_SYMBOL (style),
+			QCtype, Qxft);
 
 	  pango_font_description_free (desc);
 	  dupstring (&x_last_font_name, name);
diff --git a/src/insdel.c b/src/insdel.c
index 4463721..3b5b520 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -1997,7 +1997,6 @@ signal_before_change (ptrdiff_t start_int, ptrdiff_t end_int,
   /* Now run the before-change-functions if any.  */
   if (!NILP (Vbefore_change_functions))
     {
-      Lisp_Object args[3];
       rvoe_arg.location = &Vbefore_change_functions;
       rvoe_arg.errorp = 1;
 
@@ -2008,10 +2007,8 @@ signal_before_change (ptrdiff_t start_int, ptrdiff_t end_int,
       record_unwind_protect_ptr (reset_var_on_error, &rvoe_arg);
 
       /* Actually run the hook functions.  */
-      args[0] = Qbefore_change_functions;
-      args[1] = FETCH_START;
-      args[2] = FETCH_END;
-      Frun_hook_with_args (3, args);
+      CALLN (Frun_hook_with_args, Qbefore_change_functions,
+	     FETCH_START, FETCH_END);
 
       /* There was no error: unarm the reset_on_error.  */
       rvoe_arg.errorp = 0;
@@ -2079,7 +2076,6 @@ signal_after_change (ptrdiff_t charpos, ptrdiff_t lendel, ptrdiff_t lenins)
 
   if (!NILP (Vafter_change_functions))
     {
-      Lisp_Object args[4];
       rvoe_arg.location = &Vafter_change_functions;
       rvoe_arg.errorp = 1;
 
@@ -2087,11 +2083,9 @@ signal_after_change (ptrdiff_t charpos, ptrdiff_t lendel, ptrdiff_t lenins)
       record_unwind_protect_ptr (reset_var_on_error, &rvoe_arg);
 
       /* Actually run the hook functions.  */
-      args[0] = Qafter_change_functions;
-      XSETFASTINT (args[1], charpos);
-      XSETFASTINT (args[2], charpos + lenins);
-      XSETFASTINT (args[3], lendel);
-      Frun_hook_with_args (4, args);
+      CALLN (Frun_hook_with_args, Qafter_change_functions,
+	     make_number (charpos), make_number (charpos + lenins),
+	     make_number (lendel));
 
       /* There was no error: unarm the reset_on_error.  */
       rvoe_arg.errorp = 0;
diff --git a/src/keyboard.c b/src/keyboard.c
index 0fe2ffc..0fecafd 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1844,7 +1844,7 @@ safe_run_hooks_error (Lisp_Object error, ptrdiff_t nargs, Lisp_Object *args)
   AUTO_STRING (format, "Error in %s (%S): %S");
   Lisp_Object hook = args[0];
   Lisp_Object fun = args[1];
-  Fmessage (4, (Lisp_Object []) {format, hook, fun, error});
+  CALLN (Fmessage, format, hook, fun, error);
 
   if (SYMBOLP (hook))
     {
@@ -10734,25 +10734,25 @@ The elements of this list correspond to the arguments of
 `set-input-mode'.  */)
   (void)
 {
-  Lisp_Object val[4];
   struct frame *sf = XFRAME (selected_frame);
 
-  val[0] = interrupt_input ? Qt : Qnil;
+  Lisp_Object interrupt = interrupt_input ? Qt : Qnil;
+  Lisp_Object flow, meta;
   if (FRAME_TERMCAP_P (sf) || FRAME_MSDOS_P (sf))
     {
-      val[1] = FRAME_TTY (sf)->flow_control ? Qt : Qnil;
-      val[2] = (FRAME_TTY (sf)->meta_key == 2
-                ? make_number (0)
-                : (CURTTY ()->meta_key == 1 ? Qt : Qnil));
+      flow = FRAME_TTY (sf)->flow_control ? Qt : Qnil;
+      meta = (FRAME_TTY (sf)->meta_key == 2
+	      ? make_number (0)
+	      : (CURTTY ()->meta_key == 1 ? Qt : Qnil));
     }
   else
     {
-      val[1] = Qnil;
-      val[2] = Qt;
+      flow = Qnil;
+      meta = Qt;
     }
-  XSETFASTINT (val[3], quit_char);
+  Lisp_Object quit = make_number (quit_char);
 
-  return Flist (ARRAYELTS (val), val);
+  return list4 (interrupt, flow, meta, quit);
 }
 
 DEFUN ("posn-at-x-y", Fposn_at_x_y, Sposn_at_x_y, 2, 4, 0,
diff --git a/src/keymap.c b/src/keymap.c
index 9c7b4d2..34fe1cb 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -1292,7 +1292,7 @@ static Lisp_Object
 append_key (Lisp_Object key_sequence, Lisp_Object key)
 {
   AUTO_LIST1 (key_list, key);
-  return Fvconcat (2, ((Lisp_Object []) { key_sequence, key_list }));
+  return CALLN (Fvconcat, key_sequence, key_list);
 }
 
 /* Given a event type C which is a symbol,
@@ -2435,8 +2435,7 @@ where_is_internal (Lisp_Object definition, Lisp_Object keymaps,
       if (NILP (where_is_cache))
 	{
 	  /* We need to create the cache.  */
-	  Lisp_Object args[2];
-	  where_is_cache = Fmake_hash_table (0, args);
+	  where_is_cache = Fmake_hash_table (0, NULL);
 	  where_is_cache_keymaps = Qt;
 	}
       else
diff --git a/src/lisp.h b/src/lisp.h
index 119257b..9c781c3 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2800,6 +2800,12 @@ enum maxargs
     UNEVALLED = -1
   };
 
+/* Call a function F that accepts many args, passing it ARRAY's elements.  */
+#define CALLMANY(f, array) (f) (ARRAYELTS (array), array)
+
+/* Call a function F that accepts many args, passing it the remaining args.  */
+#define CALLN(f, ...) CALLMANY (f, ((Lisp_Object []) {__VA_ARGS__}))
+
 extern void defvar_lisp (struct Lisp_Objfwd *, const char *, Lisp_Object *);
 extern void defvar_lisp_nopro (struct Lisp_Objfwd *, const char *, Lisp_Object *);
 extern void defvar_bool (struct Lisp_Boolfwd *, const char *, bool *);
diff --git a/src/lread.c b/src/lread.c
index 7f7bd89..69ec059 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -947,7 +947,7 @@ load_warn_old_style_backquotes (Lisp_Object file)
   if (!NILP (Vold_style_backquotes))
     {
       AUTO_STRING (format, "Loading `%s': old-style backquotes detected!");
-      Fmessage (2, (Lisp_Object []) {format, file});
+      CALLN (Fmessage, format, file);
     }
 }
 
@@ -1100,12 +1100,7 @@ Return t if the file exists and loads successfully.  */)
 	{
 	  suffixes = Fget_load_suffixes ();
 	  if (NILP (must_suffix))
-	    {
-	      Lisp_Object arg[2];
-	      arg[0] = suffixes;
-	      arg[1] = Vload_file_rep_suffixes;
-	      suffixes = Fappend (2, arg);
-	    }
+	    suffixes = CALLN (Fappend, suffixes, Vload_file_rep_suffixes);
 	}
 
       fd = openp (Vload_path, file, suffixes, &found, Qnil, load_prefer_newer);
@@ -4401,12 +4396,10 @@ init_lread (void)
           /* Replace nils from EMACSLOADPATH by default.  */
           while (CONSP (elpath))
             {
-              Lisp_Object arg[2];
               elem = XCAR (elpath);
               elpath = XCDR (elpath);
-              arg[0] = Vload_path;
-              arg[1] = NILP (elem) ? default_lpath : Fcons (elem, Qnil);
-              Vload_path = Fappend (2, arg);
+              Vload_path = CALLN (Fappend, Vload_path,
+				  NILP (elem) ? default_lpath : list1 (elem));
             }
         }                       /* Fmemq (Qnil, Vload_path) */
     }
diff --git a/src/minibuf.c b/src/minibuf.c
index 0d6e2c7..3408bb9 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -1131,9 +1131,8 @@ function, instead of the usual behavior.  */)
 	    }
 
 	  AUTO_STRING (format, "%s (default %s): ");
-	  prompt = Fformat (3, ((Lisp_Object [])
-				{format, prompt,
-				 CONSP (def) ? XCAR (def) : def}));
+	  prompt = CALLN (Fformat, format, prompt,
+			  CONSP (def) ? XCAR (def) : def);
 	}
 
       result = Fcompleting_read (prompt, intern ("internal-complete-buffer"),
@@ -1141,8 +1140,7 @@ function, instead of the usual behavior.  */)
 				 Qbuffer_name_history, def, Qnil);
     }
   else
-    result = Ffuncall (4, ((Lisp_Object [])
-      { Vread_buffer_function, prompt, def, require_match }));
+    result = call3 (Vread_buffer_function, prompt, def, require_match);
   return unbind_to (count, result);
 }
 
@@ -1662,17 +1660,10 @@ Completion ignores case if the ambient value of
 See also `completing-read-function'.  */)
   (Lisp_Object prompt, Lisp_Object collection, Lisp_Object predicate, Lisp_Object require_match, Lisp_Object initial_input, Lisp_Object hist, Lisp_Object def, Lisp_Object inherit_input_method)
 {
-  Lisp_Object args[9];
-  args[0] = Fsymbol_value (intern ("completing-read-function"));
-  args[1] = prompt;
-  args[2] = collection;
-  args[3] = predicate;
-  args[4] = require_match;
-  args[5] = initial_input;
-  args[6] = hist;
-  args[7] = def;
-  args[8] = inherit_input_method;
-  return Ffuncall (9, args);
+  return CALLN (Ffuncall,
+		Fsymbol_value (intern ("completing-read-function")),
+		prompt, collection, predicate, require_match, initial_input,
+		hist, def, inherit_input_method);
 }
 
 /* Test whether TXT is an exact completion.  */
diff --git a/src/print.c b/src/print.c
index f268370..1a0aebb 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1171,12 +1171,7 @@ print_preprocess (Lisp_Object obj)
   if (PRINT_CIRCLE_CANDIDATE_P (obj))
     {
       if (!HASH_TABLE_P (Vprint_number_table))
-	{
-	  Lisp_Object args[2];
-	  args[0] = QCtest;
-	  args[1] = Qeq;
-	  Vprint_number_table = Fmake_hash_table (2, args);
-	}
+	Vprint_number_table = CALLN (Fmake_hash_table, QCtest, Qeq);
 
       /* In case print-circle is nil and print-gensym is t,
 	 add OBJ to Vprint_number_table only when OBJ is a symbol.  */
diff --git a/src/process.c b/src/process.c
index 0789f20..1d935ba 100644
--- a/src/process.c
+++ b/src/process.c
@@ -1338,7 +1338,7 @@ Returns nil if format of ADDRESS is invalid.  */)
   if (CONSP (address))
     {
       AUTO_STRING (format, "<Family %d>");
-      return Fformat (2, (Lisp_Object []) {format, Fcar (address)});
+      return CALLN (Fformat, format, Fcar (address));
     }
 
   return Qnil;
@@ -3422,7 +3422,7 @@ usage: (make-network-process &rest ARGS)  */)
     struct gcpro gcpro1;
     /* Qt denotes we have not yet called Ffind_operation_coding_system.  */
     Lisp_Object coding_systems = Qt;
-    Lisp_Object fargs[5], val;
+    Lisp_Object val;
 
     if (!NILP (tem))
       {
@@ -3445,10 +3445,10 @@ usage: (make-network-process &rest ARGS)  */)
 	  coding_systems = Qnil;
 	else
 	  {
-	    fargs[0] = Qopen_network_stream, fargs[1] = name,
-	      fargs[2] = buffer, fargs[3] = host, fargs[4] = service;
 	    GCPRO1 (proc);
-	    coding_systems = Ffind_operation_coding_system (5, fargs);
+	    coding_systems = CALLN (Ffind_operation_coding_system,
+				    Qopen_network_stream, name, buffer,
+				    host, service);
 	    UNGCPRO;
 	  }
 	if (CONSP (coding_systems))
@@ -3478,10 +3478,10 @@ usage: (make-network-process &rest ARGS)  */)
 	      coding_systems = Qnil;
 	    else
 	      {
-		fargs[0] = Qopen_network_stream, fargs[1] = name,
-		  fargs[2] = buffer, fargs[3] = host, fargs[4] = service;
 		GCPRO1 (proc);
-		coding_systems = Ffind_operation_coding_system (5, fargs);
+		coding_systems = CALLN (Ffind_operation_coding_system,
+					Qopen_network_stream, name, buffer,
+					host, service);
 		UNGCPRO;
 	      }
 	  }
@@ -4064,12 +4064,12 @@ server_accept_connection (Lisp_Object server, int channel)
 	unsigned char *ip = (unsigned char *)&saddr.in.sin_addr.s_addr;
 
 	AUTO_STRING (ipv4_format, "%d.%d.%d.%d");
-	host = Fformat (5, ((Lisp_Object [])
-	  { ipv4_format, make_number (ip[0]),
-	    make_number (ip[1]), make_number (ip[2]), make_number (ip[3]) }));
+	host = CALLN (Fformat, ipv4_format,
+		      make_number (ip[0]), make_number (ip[1]),
+		      make_number (ip[2]), make_number (ip[3]));
 	service = make_number (ntohs (saddr.in.sin_port));
 	AUTO_STRING (caller_format, " <%s:%d>");
-	caller = Fformat (3, (Lisp_Object []) {caller_format, host, service});
+	caller = CALLN (Fformat, caller_format, host, service);
       }
       break;
 
@@ -4084,10 +4084,10 @@ server_accept_connection (Lisp_Object server, int channel)
 	args[0] = ipv6_format;
 	for (i = 0; i < 8; i++)
 	  args[i + 1] = make_number (ntohs (ip6[i]));
-	host = Fformat (9, args);
+	host = CALLMANY (Fformat, args);
 	service = make_number (ntohs (saddr.in.sin_port));
 	AUTO_STRING (caller_format, " <[%s]:%d>");
-	caller = Fformat (3, (Lisp_Object []) {caller_format, host, service});
+	caller = CALLN (Fformat, caller_format, host, service);
       }
       break;
 #endif
diff --git a/src/sound.c b/src/sound.c
index 6f7e2ad..d756ec5 100644
--- a/src/sound.c
+++ b/src/sound.c
@@ -1352,7 +1352,6 @@ Internal use only, use `play-sound' instead.  */)
   Lisp_Object attrs[SOUND_ATTR_SENTINEL];
   ptrdiff_t count = SPECPDL_INDEX ();
   Lisp_Object file;
-  Lisp_Object args[2];
   struct gcpro gcpro1, gcpro2;
 
 #ifdef WINDOWSNT
@@ -1407,9 +1406,7 @@ Internal use only, use `play-sound' instead.  */)
   else if (FLOATP (attrs[SOUND_VOLUME]))
     current_sound_device->volume = XFLOAT_DATA (attrs[SOUND_VOLUME]) * 100;
 
-  args[0] = Qplay_sound_functions;
-  args[1] = sound;
-  Frun_hook_with_args (2, args);
+  CALLN (Frun_hook_with_args, Qplay_sound_functions, sound);
 
 #ifdef HAVE_ALSA
   if (!alsa_init (current_sound_device))
@@ -1441,9 +1438,7 @@ Internal use only, use `play-sound' instead.  */)
 
   GCPRO2 (sound, file);
 
-  args[0] = Qplay_sound_functions;
-  args[1] = sound;
-  Frun_hook_with_args (2, args);
+  CALLN (Frun_hook_with_args, Qplay_sound_functions, sound);
 
   /*
     Based on some experiments I have conducted, a value of 100 or less
diff --git a/src/term.c b/src/term.c
index d48bf7b..15d33b4 100644
--- a/src/term.c
+++ b/src/term.c
@@ -2253,10 +2253,9 @@ A suspended tty may be resumed by calling `resume-tty' on it.  */)
       /* First run `suspend-tty-functions' and then clean up the tty
 	 state because `suspend-tty-functions' might need to change
 	 the tty state.  */
-      Lisp_Object args[2];
-      args[0] = intern ("suspend-tty-functions");
-      XSETTERMINAL (args[1], t);
-      Frun_hook_with_args (2, args);
+      Lisp_Object term;
+      XSETTERMINAL (term, t);
+      CALLN (Frun_hook_with_args, intern ("suspend-tty-functions"), term);
 
       reset_sys_modes (t->display_info.tty);
       delete_keyboard_wait_descriptor (fileno (f));
@@ -2353,13 +2352,10 @@ frame's terminal). */)
       set_tty_hooks (t);
       init_sys_modes (t->display_info.tty);
 
-      {
-        /* Run `resume-tty-functions'.  */
-        Lisp_Object args[2];
-        args[0] = intern ("resume-tty-functions");
-        XSETTERMINAL (args[1], t);
-        Frun_hook_with_args (2, args);
-      }
+      /* Run `resume-tty-functions'.  */
+      Lisp_Object term;
+      XSETTERMINAL (term, t);
+      CALLN (Frun_hook_with_args, intern ("resume-tty-functions"), term);
     }
 
   set_tty_hooks (t);
diff --git a/src/window.c b/src/window.c
index 53a235f..2f44bf7 100644
--- a/src/window.c
+++ b/src/window.c
@@ -2426,16 +2426,14 @@ window_list (void)
       Vwindow_list = Qnil;
       FOR_EACH_FRAME (tail, frame)
 	{
-	  Lisp_Object args[2];
+	  Lisp_Object arglist = Qnil;
 
 	  /* We are visiting windows in canonical order, and add
 	     new windows at the front of args[1], which means we
 	     have to reverse this list at the end.  */
-	  args[1] = Qnil;
-	  foreach_window (XFRAME (frame), add_window_to_list, &args[1]);
-	  args[0] = Vwindow_list;
-	  args[1] = Fnreverse (args[1]);
-	  Vwindow_list = Fnconc (2, args);
+	  foreach_window (XFRAME (frame), add_window_to_list, &arglist);
+	  arglist = Fnreverse (arglist);
+	  Vwindow_list = CALLN (Fnconc, Vwindow_list, arglist);
 	}
     }
 
diff --git a/src/xdisp.c b/src/xdisp.c
index 9abaeb0..5767286 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -8295,22 +8295,18 @@ next_element_from_buffer (struct it *it)
 static void
 run_redisplay_end_trigger_hook (struct it *it)
 {
-  Lisp_Object args[3];
-
   /* IT->glyph_row should be non-null, i.e. we should be actually
      displaying something, or otherwise we should not run the hook.  */
   eassert (it->glyph_row);
 
-  /* Set up hook arguments.  */
-  args[0] = Qredisplay_end_trigger_functions;
-  args[1] = it->window;
-  XSETINT (args[2], it->redisplay_end_trigger_charpos);
+  ptrdiff_t charpos = it->redisplay_end_trigger_charpos;
   it->redisplay_end_trigger_charpos = 0;
 
   /* Since we are *trying* to run these functions, don't try to run
      them again, even if they get an error.  */
   wset_redisplay_end_trigger (it->w, Qnil);
-  Frun_hook_with_args (3, args);
+  CALLN (Frun_hook_with_args, Qredisplay_end_trigger_functions, it->window,
+	 make_number (charpos));
 
   /* Notice if it changed the face of the character we are on.  */
   handle_face_prop (it);
@@ -9809,7 +9805,6 @@ include the height of both, if present, in the return value.  */)
 void
 add_to_log (const char *format, Lisp_Object arg1, Lisp_Object arg2)
 {
-  Lisp_Object args[3];
   Lisp_Object msg, fmt;
   char *buffer;
   ptrdiff_t len;
@@ -9819,10 +9814,8 @@ add_to_log (const char *format, Lisp_Object arg1, Lisp_Object arg2)
   fmt = msg = Qnil;
   GCPRO4 (fmt, msg, arg1, arg2);
 
-  args[0] = fmt = build_string (format);
-  args[1] = arg1;
-  args[2] = arg2;
-  msg = Fformat (3, args);
+  fmt = build_string (format);
+  msg = CALLN (Fformat, fmt, arg1, arg2);
 
   len = SBYTES (msg) + 1;
   buffer = SAFE_ALLOCA (len);
@@ -10237,15 +10230,13 @@ message_with_string (const char *m, Lisp_Object string, int log)
 	 initialized yet, just toss it.  */
       if (f->glyphs_initialized_p)
 	{
-	  Lisp_Object args[2], msg;
 	  struct gcpro gcpro1, gcpro2;
 
-	  args[0] = build_string (m);
-	  args[1] = msg = string;
-	  GCPRO2 (args[0], msg);
-	  gcpro1.nvars = 2;
+	  Lisp_Object fmt = build_string (m);
+	  Lisp_Object msg = string;
+	  GCPRO2 (fmt, msg);
 
-	  msg = Fformat (2, args);
+	  msg = CALLN (Fformat, fmt, msg);
 
 	  if (log)
 	    message3 (msg);
diff --git a/src/xfaces.c b/src/xfaces.c
index 85af770..1ba6b51 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -1580,43 +1580,38 @@ the WIDTH times as wide as FACE on FRAME.  */)
 	avgwidth *= XINT (width);
     }
 
-  {
-    Lisp_Object font_spec;
-    Lisp_Object args[2], tail;
-
-    font_spec = font_spec_from_name (pattern);
-    if (!FONTP (font_spec))
-      signal_error ("Invalid font name", pattern);
+  Lisp_Object font_spec = font_spec_from_name (pattern);
+  if (!FONTP (font_spec))
+    signal_error ("Invalid font name", pattern);
 
-    if (size)
-      {
-	Ffont_put (font_spec, QCsize, make_number (size));
-	Ffont_put (font_spec, QCavgwidth, make_number (avgwidth));
-      }
-    args[0] = Flist_fonts (font_spec, frame, maximum, font_spec);
-    for (tail = args[0]; CONSP (tail); tail = XCDR (tail))
-      {
-	Lisp_Object font_entity;
+  if (size)
+    {
+      Ffont_put (font_spec, QCsize, make_number (size));
+      Ffont_put (font_spec, QCavgwidth, make_number (avgwidth));
+    }
+  Lisp_Object fonts = Flist_fonts (font_spec, frame, maximum, font_spec);
+  for (Lisp_Object tail = fonts; CONSP (tail); tail = XCDR (tail))
+    {
+      Lisp_Object font_entity;
 
-	font_entity = XCAR (tail);
-	if ((NILP (AREF (font_entity, FONT_SIZE_INDEX))
-	     || XINT (AREF (font_entity, FONT_SIZE_INDEX)) == 0)
-	    && ! NILP (AREF (font_spec, FONT_SIZE_INDEX)))
-	  {
-	    /* This is a scalable font.  For backward compatibility,
-	       we set the specified size. */
-	    font_entity = copy_font_spec (font_entity);
-	    ASET (font_entity, FONT_SIZE_INDEX,
-		  AREF (font_spec, FONT_SIZE_INDEX));
-	  }
-	XSETCAR (tail, Ffont_xlfd_name (font_entity, Qnil));
-      }
-    if (NILP (frame))
-      /* We don't have to check fontsets.  */
-      return args[0];
-    args[1] = list_fontsets (f, pattern, size);
-    return Fnconc (2, args);
-  }
+      font_entity = XCAR (tail);
+      if ((NILP (AREF (font_entity, FONT_SIZE_INDEX))
+	   || XINT (AREF (font_entity, FONT_SIZE_INDEX)) == 0)
+	  && ! NILP (AREF (font_spec, FONT_SIZE_INDEX)))
+	{
+	  /* This is a scalable font.  For backward compatibility,
+	     we set the specified size. */
+	  font_entity = copy_font_spec (font_entity);
+	  ASET (font_entity, FONT_SIZE_INDEX,
+		AREF (font_spec, FONT_SIZE_INDEX));
+	}
+      XSETCAR (tail, Ffont_xlfd_name (font_entity, Qnil));
+    }
+  if (NILP (frame))
+    /* We don't have to check fontsets.  */
+    return fonts;
+  Lisp_Object fontsets = list_fontsets (f, pattern, size);
+  return CALLN (Fnconc, fonts, fontsets);
 }
 
 #endif /* HAVE_WINDOW_SYSTEM */
diff --git a/src/xfont.c b/src/xfont.c
index 10cc321..d0bafc2 100644
--- a/src/xfont.c
+++ b/src/xfont.c
@@ -1106,13 +1106,7 @@ void
 syms_of_xfont (void)
 {
   staticpro (&xfont_scripts_cache);
-  { /* Here we rely on the fact that syms_of_xfont (via syms_of_font)
-       is called fairly late, when QCtest and Qequal are known to be set.  */
-    Lisp_Object args[2];
-    args[0] = QCtest;
-    args[1] = Qequal;
-    xfont_scripts_cache = Fmake_hash_table (2, args);
-  }
+  xfont_scripts_cache = CALLN (Fmake_hash_table, QCtest, Qequal);
   staticpro (&xfont_scratch_props);
   xfont_scratch_props = Fmake_vector (make_number (8), Qnil);
   xfont_driver.type = Qx;
diff --git a/src/xselect.c b/src/xselect.c
index 33ff366..027192d 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -817,14 +817,8 @@ x_handle_selection_request (struct input_event *event)
   /* Run the `x-sent-selection-functions' abnormal hook.  */
   if (!NILP (Vx_sent_selection_functions)
       && !EQ (Vx_sent_selection_functions, Qunbound))
-    {
-      Lisp_Object args[4];
-      args[0] = Qx_sent_selection_functions;
-      args[1] = selection_symbol;
-      args[2] = target_symbol;
-      args[3] = success ? Qt : Qnil;
-      Frun_hook_with_args (4, args);
-    }
+    CALLN (Frun_hook_with_args, Qx_sent_selection_functions,
+	   selection_symbol, target_symbol, success ? Qt : Qnil);
 
   unbind_to (count, Qnil);
   UNGCPRO;
@@ -937,12 +931,7 @@ x_handle_selection_clear (struct input_event *event)
   tset_selection_alist (dpyinfo->terminal, Vselection_alist);
 
   /* Run the `x-lost-selection-functions' abnormal hook.  */
-  {
-    Lisp_Object args[2];
-    args[0] = Qx_lost_selection_functions;
-    args[1] = selection_symbol;
-    Frun_hook_with_args (2, args);
-  }
+  CALLN (Frun_hook_with_args, Qx_lost_selection_functions, selection_symbol);
 
   redisplay_preserve_echo_area (20);
 }
@@ -978,10 +967,8 @@ x_clear_frame_selections (struct frame *f)
 	 && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (t->Vselection_alist)))))))
     {
       /* Run the `x-lost-selection-functions' abnormal hook.  */
-      Lisp_Object args[2];
-      args[0] = Qx_lost_selection_functions;
-      args[1] = Fcar (Fcar (t->Vselection_alist));
-      Frun_hook_with_args (2, args);
+      CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
+	     Fcar (Fcar (t->Vselection_alist)));
 
       tset_selection_alist (t, XCDR (t->Vselection_alist));
     }
@@ -991,10 +978,8 @@ x_clear_frame_selections (struct frame *f)
     if (CONSP (XCDR (rest))
 	&& EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (XCDR (rest))))))))
       {
-	Lisp_Object args[2];
-	args[0] = Qx_lost_selection_functions;
-	args[1] = XCAR (XCAR (XCDR (rest)));
-	Frun_hook_with_args (2, args);
+	CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
+	       XCAR (XCAR (XCDR (rest))));
 	XSETCDR (rest, XCDR (XCDR (rest)));
 	break;
       }
@@ -2138,7 +2123,7 @@ x_clipboard_manager_error_1 (Lisp_Object err)
 {
   AUTO_STRING (format, "X clipboard manager error: %s\n\
 If the problem persists, set `x-select-enable-clipboard-manager' to nil.");
-  Fmessage (2, (Lisp_Object []) {format, CAR (CDR (err))});
+  CALLN (Fmessage, format, CAR (CDR (err)));
   return Qnil;
 }