unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#19634: counting MANY function args more reliably
@ 2015-01-20  9:26 Paul Eggert
  2015-01-20 16:37 ` Stefan Monnier
  0 siblings, 1 reply; 6+ messages in thread
From: Paul Eggert @ 2015-01-20  9:26 UTC (permalink / raw)
  To: 19634

[-- Attachment #1: Type: text/plain, Size: 1075 bytes --]

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.

[-- Attachment #2: calln.diff --]
[-- Type: text/x-patch, Size: 64992 bytes --]

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);
 }
 \f
 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);
 }
 \f
@@ -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);
 }
 \f
 /* 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;
 }
 

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* bug#19634: counting MANY function args more reliably
  2015-01-20  9:26 bug#19634: counting MANY function args more reliably Paul Eggert
@ 2015-01-20 16:37 ` Stefan Monnier
  2015-01-22 16:31   ` Eli Zaretskii
  2015-01-25 17:15   ` Paul Eggert
  0 siblings, 2 replies; 6+ messages in thread
From: Stefan Monnier @ 2015-01-20 16:37 UTC (permalink / raw)
  To: Paul Eggert; +Cc: 19634

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

I like that,


        Stefan





^ permalink raw reply	[flat|nested] 6+ messages in thread

* bug#19634: counting MANY function args more reliably
  2015-01-20 16:37 ` Stefan Monnier
@ 2015-01-22 16:31   ` Eli Zaretskii
  2015-01-22 17:42     ` Paul Eggert
  2015-01-25 17:15   ` Paul Eggert
  1 sibling, 1 reply; 6+ messages in thread
From: Eli Zaretskii @ 2015-01-22 16:31 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 19634, eggert

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Date: Tue, 20 Jan 2015 11:37:39 -0500
> Cc: 19634@debbugs.gnu.org
> 
> > #define CALLN(f, ...) CALLMANY (f, ((Lisp_Object []) {__VA_ARGS__}))
> 
> I like that,

Do we want to use this for every call to a function that accepts MANY
args, or just those where the argument is an array?

I'm asking because the proposed patch left out this part of w32fns.c:

  static Lisp_Object
  x_create_tip_frame (struct w32_display_info *dpyinfo,
		      Lisp_Object parms, Lisp_Object text)
  {
    [...]
    Ferase_buffer ();
    Finsert (1, &text);  <<<<<<<<<<<<<<<<<<<<<<

and I'm not sure whether this was just an omission or this kind of
calls doesn't need to use CALLN.





^ permalink raw reply	[flat|nested] 6+ messages in thread

* bug#19634: counting MANY function args more reliably
  2015-01-22 16:31   ` Eli Zaretskii
@ 2015-01-22 17:42     ` Paul Eggert
  2015-01-22 18:16       ` Eli Zaretskii
  0 siblings, 1 reply; 6+ messages in thread
From: Paul Eggert @ 2015-01-22 17:42 UTC (permalink / raw)
  To: Eli Zaretskii, Stefan Monnier; +Cc: 19634

On 01/22/2015 08:31 AM, Eli Zaretskii wrote:
> Do we want to use this for every call to a function that accepts MANY
> args, or just those where the argument is an array?

We should use it for calls where counting the number of arguments is 
likely to be error-prone.

> I'm asking because the proposed patch left out this part of w32fns.c:
>
>    static Lisp_Object
>    x_create_tip_frame (struct w32_display_info *dpyinfo,
> 		      Lisp_Object parms, Lisp_Object text)
>    {
>      [...]
>      Ferase_buffer ();
>      Finsert (1, &text);  <<<<<<<<<<<<<<<<<<<<<<

The patch does not affect calls like that, as they're unlikely to give 
rise to the sort of typographical error that motivated the patch.





^ permalink raw reply	[flat|nested] 6+ messages in thread

* bug#19634: counting MANY function args more reliably
  2015-01-22 17:42     ` Paul Eggert
@ 2015-01-22 18:16       ` Eli Zaretskii
  0 siblings, 0 replies; 6+ messages in thread
From: Eli Zaretskii @ 2015-01-22 18:16 UTC (permalink / raw)
  To: Paul Eggert; +Cc: 19634

> Date: Thu, 22 Jan 2015 09:42:10 -0800
> From: Paul Eggert <eggert@cs.ucla.edu>
> CC: 19634@debbugs.gnu.org
> 
> On 01/22/2015 08:31 AM, Eli Zaretskii wrote:
> > Do we want to use this for every call to a function that accepts MANY
> > args, or just those where the argument is an array?
> 
> We should use it for calls where counting the number of arguments is 
> likely to be error-prone.
> 
> > I'm asking because the proposed patch left out this part of w32fns.c:
> >
> >    static Lisp_Object
> >    x_create_tip_frame (struct w32_display_info *dpyinfo,
> > 		      Lisp_Object parms, Lisp_Object text)
> >    {
> >      [...]
> >      Ferase_buffer ();
> >      Finsert (1, &text);  <<<<<<<<<<<<<<<<<<<<<<
> 
> The patch does not affect calls like that, as they're unlikely to give 
> rise to the sort of typographical error that motivated the patch.

OK, thanks.





^ permalink raw reply	[flat|nested] 6+ messages in thread

* bug#19634: counting MANY function args more reliably
  2015-01-20 16:37 ` Stefan Monnier
  2015-01-22 16:31   ` Eli Zaretskii
@ 2015-01-25 17:15   ` Paul Eggert
  1 sibling, 0 replies; 6+ messages in thread
From: Paul Eggert @ 2015-01-25 17:15 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 19634-done

Stefan Monnier wrote:
> I like that,

Thanks, I tested the patch on a few more platforms, rebased it to the current 
master, added some commentary in response to the remarks in this bug report, and 
installed the patch into the master as commit 
a3689d3c661fe36df971c875760f8d500b5ae994.





^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-01-25 17:15 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-01-20  9:26 bug#19634: counting MANY function args more reliably Paul Eggert
2015-01-20 16:37 ` Stefan Monnier
2015-01-22 16:31   ` Eli Zaretskii
2015-01-22 17:42     ` Paul Eggert
2015-01-22 18:16       ` Eli Zaretskii
2015-01-25 17:15   ` Paul Eggert

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).