aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2014-09-29 19:43:23 -0700
committerPaul Eggert2014-09-29 19:43:23 -0700
commitdc4525691c2c236abdb6c074438223413f80091c (patch)
tree86305e7415bcf1b5cc6ddad6879e922f9e5e163c /src
parenta19f0977a96ee74b96410b41a8ea793c86f64b58 (diff)
downloademacs-dc4525691c2c236abdb6c074438223413f80091c.tar.gz
emacs-dc4525691c2c236abdb6c074438223413f80091c.zip
Simplify stack-allocated Lisp objects, and make them more portable.
The build_local_string macro was used in two ways: (1) string literals for which scoped allocation suffices, and (2) file name components, where it's not safe in general to assume bounded-size ASCII data. Simplify by defining a new macro SCOPED_STRING that allocates a block-scope string, and by using SCOPED_STRING for (1) and build_string for (2). Furthermore, actually use stack allocation only for objects known to have sufficient alignment. This simpler implementation means Emacs can make USE_STACK_LISP_OBJECTS the default unless GC_MARK_STACK != GC_MAKE_GCPROS_NOOPS. * lisp.h (GCALIGNED): Align even if !USE_STACK_LISP_OBJECTS, for fewer differences among implementations. (struct Lisp_String): Now GCALIGNED. (USE_STACK_LISP_OBJECTS): Default to true, since the implementation no longer insists on a nonempty GCALIGNED. But make it false if GC_MARK_STACK != GC_MAKE_GCPROS_NOOPS. (SCOPED_CONS_INITIALIZER): Remove, since it's no longer needed separately. Move definiens to scoped_cons. The old definition was incorrect when GCALIGNED was defined to be empty. (union Aligned_String): New type. (USE_STACK_CONS, USE_STACK_STRING): New constants, so that the implementation ports to compilers that don't align strictly enough. Don't worry about the union sizes; it's not worth bothering about. (scoped_cons, scoped_list1, scoped_list3, scoped_list4): Rewrite using USE_STACK_CONS. (scoped_cons): Assume the use of union Aligned_Cons. (lisp_string_size, make_local_string, build_local_string): Remove. Unless otherwise specified, all callers of build_local_string changed to use SCOPED_STRING. (SCOPED_STRING): New macro. * data.c (wrong_choice): * menu.c (single_menu_item): * process.c (Fformat_network_address): Hoist use of SCOPED_STRING out of a scope, so that its returned object lives long enough. * fileio.c (Fexpand_file_name): Use build_string, not SCOPED_STRING, as the string might be long or might not be ASCII.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog41
-rw-r--r--src/buffer.c12
-rw-r--r--src/charset.c3
-rw-r--r--src/chartab.c2
-rw-r--r--src/data.c14
-rw-r--r--src/doc.c4
-rw-r--r--src/editfns.c3
-rw-r--r--src/emacs.c6
-rw-r--r--src/fileio.c14
-rw-r--r--src/fns.c2
-rw-r--r--src/font.c14
-rw-r--r--src/fontset.c2
-rw-r--r--src/frame.c4
-rw-r--r--src/keyboard.c16
-rw-r--r--src/keymap.c6
-rw-r--r--src/lisp.h166
-rw-r--r--src/lread.c4
-rw-r--r--src/menu.c16
-rw-r--r--src/minibuf.c2
-rw-r--r--src/process.c45
-rw-r--r--src/xdisp.c2
-rw-r--r--src/xfns.c10
-rw-r--r--src/xselect.c4
-rw-r--r--src/xterm.c12
24 files changed, 201 insertions, 203 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index d2d629f31b4..ae4200e7d09 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,44 @@
12014-09-30 Paul Eggert <eggert@cs.ucla.edu>
2
3 Simplify stack-allocated Lisp objects, and make them more portable.
4 The build_local_string macro was used in two ways: (1) string
5 literals for which scoped allocation suffices, and (2) file name
6 components, where it's not safe in general to assume bounded-size
7 ASCII data. Simplify by defining a new macro SCOPED_STRING that
8 allocates a block-scope string, and by using SCOPED_STRING for (1)
9 and build_string for (2). Furthermore, actually use stack
10 allocation only for objects known to have sufficient alignment.
11 This simpler implementation means Emacs can make
12 USE_STACK_LISP_OBJECTS the default unless GC_MARK_STACK !=
13 GC_MAKE_GCPROS_NOOPS.
14 * lisp.h (GCALIGNED): Align even if !USE_STACK_LISP_OBJECTS,
15 for fewer differences among implementations.
16 (struct Lisp_String): Now GCALIGNED.
17 (USE_STACK_LISP_OBJECTS): Default to true, since the
18 implementation no longer insists on a nonempty GCALIGNED.
19 But make it false if GC_MARK_STACK != GC_MAKE_GCPROS_NOOPS.
20 (SCOPED_CONS_INITIALIZER): Remove, since it's no longer needed
21 separately. Move definiens to scoped_cons. The old definition
22 was incorrect when GCALIGNED was defined to be empty.
23 (union Aligned_String): New type.
24 (USE_STACK_CONS, USE_STACK_STRING): New constants, so that the
25 implementation ports to compilers that don't align strictly enough.
26 Don't worry about the union sizes; it's not worth bothering about.
27 (scoped_cons, scoped_list1, scoped_list3, scoped_list4):
28 Rewrite using USE_STACK_CONS.
29 (scoped_cons): Assume the use of union Aligned_Cons.
30 (lisp_string_size, make_local_string, build_local_string): Remove.
31 Unless otherwise specified, all callers of build_local_string
32 changed to use SCOPED_STRING.
33 (SCOPED_STRING): New macro.
34 * data.c (wrong_choice):
35 * menu.c (single_menu_item):
36 * process.c (Fformat_network_address):
37 Hoist use of SCOPED_STRING out of a scope, so that its returned
38 object lives long enough.
39 * fileio.c (Fexpand_file_name): Use build_string, not SCOPED_STRING,
40 as the string might be long or might not be ASCII.
41
12014-09-29 Eli Zaretskii <eliz@gnu.org> 422014-09-29 Eli Zaretskii <eliz@gnu.org>
2 43
3 * msdos.c (internal_terminal_init): Bump version to 25. 44 * msdos.c (internal_terminal_init): Bump version to 25.
diff --git a/src/buffer.c b/src/buffer.c
index 39d08950bf8..9d376346a0a 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1552,10 +1552,10 @@ exists, return the buffer `*scratch*' (creating it if necessary). */)
1552 return notsogood; 1552 return notsogood;
1553 else 1553 else
1554 { 1554 {
1555 buf = Fget_buffer (build_local_string ("*scratch*")); 1555 buf = Fget_buffer (SCOPED_STRING ("*scratch*"));
1556 if (NILP (buf)) 1556 if (NILP (buf))
1557 { 1557 {
1558 buf = Fget_buffer_create (build_local_string ("*scratch*")); 1558 buf = Fget_buffer_create (SCOPED_STRING ("*scratch*"));
1559 Fset_buffer_major_mode (buf); 1559 Fset_buffer_major_mode (buf);
1560 } 1560 }
1561 return buf; 1561 return buf;
@@ -1575,10 +1575,10 @@ other_buffer_safely (Lisp_Object buffer)
1575 if (candidate_buffer (buf, buffer)) 1575 if (candidate_buffer (buf, buffer))
1576 return buf; 1576 return buf;
1577 1577
1578 buf = Fget_buffer (build_local_string ("*scratch*")); 1578 buf = Fget_buffer (SCOPED_STRING ("*scratch*"));
1579 if (NILP (buf)) 1579 if (NILP (buf))
1580 { 1580 {
1581 buf = Fget_buffer_create (build_local_string ("*scratch*")); 1581 buf = Fget_buffer_create (SCOPED_STRING ("*scratch*"));
1582 Fset_buffer_major_mode (buf); 1582 Fset_buffer_major_mode (buf);
1583 } 1583 }
1584 1584
@@ -5289,7 +5289,7 @@ init_buffer (int initialized)
5289 (void) initialized; 5289 (void) initialized;
5290#endif /* USE_MMAP_FOR_BUFFERS */ 5290#endif /* USE_MMAP_FOR_BUFFERS */
5291 5291
5292 Fset_buffer (Fget_buffer_create (build_local_string ("*scratch*"))); 5292 Fset_buffer (Fget_buffer_create (SCOPED_STRING ("*scratch*")));
5293 if (NILP (BVAR (&buffer_defaults, enable_multibyte_characters))) 5293 if (NILP (BVAR (&buffer_defaults, enable_multibyte_characters)))
5294 Fset_buffer_multibyte (Qnil); 5294 Fset_buffer_multibyte (Qnil);
5295 5295
@@ -5328,7 +5328,7 @@ init_buffer (int initialized)
5328 && strcmp ("/", SSDATA (BVAR (current_buffer, directory)))) 5328 && strcmp ("/", SSDATA (BVAR (current_buffer, directory))))
5329 bset_directory 5329 bset_directory
5330 (current_buffer, 5330 (current_buffer,
5331 concat2 (build_local_string ("/:"), BVAR (current_buffer, directory))); 5331 concat2 (SCOPED_STRING ("/:"), BVAR (current_buffer, directory)));
5332 5332
5333 temp = get_minibuffer (0); 5333 temp = get_minibuffer (0);
5334 bset_directory (XBUFFER (temp), BVAR (current_buffer, directory)); 5334 bset_directory (XBUFFER (temp), BVAR (current_buffer, directory));
diff --git a/src/charset.c b/src/charset.c
index 9fe3548be08..dee67a30c2e 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -490,8 +490,7 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile,
490 int n_entries; 490 int n_entries;
491 ptrdiff_t count; 491 ptrdiff_t count;
492 492
493 suffixes = scoped_list2 (build_local_string (".map"), 493 suffixes = scoped_list2 (SCOPED_STRING (".map"), SCOPED_STRING (".TXT"));
494 build_local_string (".TXT"));
495 494
496 count = SPECPDL_INDEX (); 495 count = SPECPDL_INDEX ();
497 record_unwind_protect_nothing (); 496 record_unwind_protect_nothing ();
diff --git a/src/chartab.c b/src/chartab.c
index 4e4219d8ae3..35362e32a03 100644
--- a/src/chartab.c
+++ b/src/chartab.c
@@ -1302,7 +1302,7 @@ uniprop_table (Lisp_Object prop)
1302 { 1302 {
1303 struct gcpro gcpro1; 1303 struct gcpro gcpro1;
1304 GCPRO1 (val); 1304 GCPRO1 (val);
1305 result = Fload (concat2 (build_local_string ("international/"), table), 1305 result = Fload (concat2 (SCOPED_STRING ("international/"), table),
1306 Qt, Qt, Qt, Qt); 1306 Qt, Qt, Qt, Qt);
1307 UNGCPRO; 1307 UNGCPRO;
1308 if (NILP (result)) 1308 if (NILP (result))
diff --git a/src/data.c b/src/data.c
index 414da4cf6f7..b71d88506d0 100644
--- a/src/data.c
+++ b/src/data.c
@@ -979,18 +979,20 @@ wrong_choice (Lisp_Object choice, Lisp_Object wrong)
979{ 979{
980 ptrdiff_t i = 0, len = XINT (Flength (choice)); 980 ptrdiff_t i = 0, len = XINT (Flength (choice));
981 Lisp_Object obj, *args; 981 Lisp_Object obj, *args;
982 Lisp_Object should_be_specified = SCOPED_STRING (" should be specified");
983 Lisp_Object or = SCOPED_STRING (" or ");
984 Lisp_Object comma = SCOPED_STRING (", ");
982 985
983 USE_SAFE_ALLOCA; 986 USE_SAFE_ALLOCA;
984 SAFE_ALLOCA_LISP (args, len * 2 + 1); 987 SAFE_ALLOCA_LISP (args, len * 2 + 1);
985 988
986 args[i++] = build_local_string ("One of "); 989 args[i++] = SCOPED_STRING ("One of ");
987 990
988 for (obj = choice; !NILP (obj); obj = XCDR (obj)) 991 for (obj = choice; !NILP (obj); obj = XCDR (obj))
989 { 992 {
990 args[i++] = SYMBOL_NAME (XCAR (obj)); 993 args[i++] = SYMBOL_NAME (XCAR (obj));
991 args[i++] = build_local_string 994 args[i++] = (NILP (XCDR (obj)) ? should_be_specified
992 (NILP (XCDR (obj)) ? " should be specified" 995 : NILP (XCDR (XCDR (obj))) ? or : comma);
993 : (NILP (XCDR (XCDR (obj))) ? " or " : ", "));
994 } 996 }
995 997
996 obj = Fconcat (i, args); 998 obj = Fconcat (i, args);
@@ -1005,9 +1007,9 @@ static void
1005wrong_range (Lisp_Object min, Lisp_Object max, Lisp_Object wrong) 1007wrong_range (Lisp_Object min, Lisp_Object max, Lisp_Object wrong)
1006{ 1008{
1007 xsignal2 (Qerror, Fconcat (4, ((Lisp_Object []) 1009 xsignal2 (Qerror, Fconcat (4, ((Lisp_Object [])
1008 { build_local_string ("Value should be from "), 1010 { SCOPED_STRING ("Value should be from "),
1009 Fnumber_to_string (min), 1011 Fnumber_to_string (min),
1010 build_local_string (" to "), 1012 SCOPED_STRING (" to "),
1011 Fnumber_to_string (max) })), wrong); 1013 Fnumber_to_string (max) })), wrong);
1012} 1014}
1013 1015
diff --git a/src/doc.c b/src/doc.c
index bbb42c2aa3f..8af2c82a545 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -146,8 +146,8 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
146 if (fd < 0) 146 if (fd < 0)
147 { 147 {
148 SAFE_FREE (); 148 SAFE_FREE ();
149 return concat3 (build_local_string ("Cannot open doc string file \""), 149 return concat3 (SCOPED_STRING ("Cannot open doc string file \""),
150 file, build_local_string ("\"\n")); 150 file, SCOPED_STRING ("\"\n"));
151 } 151 }
152 } 152 }
153 count = SPECPDL_INDEX (); 153 count = SPECPDL_INDEX ();
diff --git a/src/editfns.c b/src/editfns.c
index 47779914c45..b8a0f6fe637 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -4362,8 +4362,7 @@ usage: (format STRING &rest OBJECTS) */)
4362Lisp_Object 4362Lisp_Object
4363format2 (const char *string1, Lisp_Object arg0, Lisp_Object arg1) 4363format2 (const char *string1, Lisp_Object arg0, Lisp_Object arg1)
4364{ 4364{
4365 return Fformat (3, ((Lisp_Object []) 4365 return Fformat (3, (Lisp_Object []) { SCOPED_STRING (string1), arg0, arg1 });
4366 { build_local_string (string1), arg0, arg1 }));
4367} 4366}
4368 4367
4369DEFUN ("char-equal", Fchar_equal, Schar_equal, 2, 2, 0, 4368DEFUN ("char-equal", Fchar_equal, Schar_equal, 2, 2, 0,
diff --git a/src/emacs.c b/src/emacs.c
index 241479fecf2..3c31827e994 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -423,7 +423,7 @@ init_cmdargs (int argc, char **argv, int skip_args, char *original_pwd)
423 if it would otherwise be treated as magic. */ 423 if it would otherwise be treated as magic. */
424 handler = Ffind_file_name_handler (raw_name, Qt); 424 handler = Ffind_file_name_handler (raw_name, Qt);
425 if (! NILP (handler)) 425 if (! NILP (handler))
426 raw_name = concat2 (build_local_string ("/:"), raw_name); 426 raw_name = concat2 (SCOPED_STRING ("/:"), raw_name);
427 427
428 Vinvocation_name = Ffile_name_nondirectory (raw_name); 428 Vinvocation_name = Ffile_name_nondirectory (raw_name);
429 Vinvocation_directory = Ffile_name_directory (raw_name); 429 Vinvocation_directory = Ffile_name_directory (raw_name);
@@ -441,7 +441,7 @@ init_cmdargs (int argc, char **argv, int skip_args, char *original_pwd)
441 if it would otherwise be treated as magic. */ 441 if it would otherwise be treated as magic. */
442 handler = Ffind_file_name_handler (found, Qt); 442 handler = Ffind_file_name_handler (found, Qt);
443 if (! NILP (handler)) 443 if (! NILP (handler))
444 found = concat2 (build_local_string ("/:"), found); 444 found = concat2 (SCOPED_STRING ("/:"), found);
445 Vinvocation_directory = Ffile_name_directory (found); 445 Vinvocation_directory = Ffile_name_directory (found);
446 } 446 }
447 } 447 }
@@ -2323,7 +2323,7 @@ decode_env_path (const char *evarname, const char *defalt, bool empty)
2323 } 2323 }
2324 2324
2325 if (! NILP (tem)) 2325 if (! NILP (tem))
2326 element = concat2 (build_local_string ("/:"), element); 2326 element = concat2 (SCOPED_STRING ("/:"), element);
2327 } /* !NILP (element) */ 2327 } /* !NILP (element) */
2328 2328
2329 lpath = Fcons (element, lpath); 2329 lpath = Fcons (element, lpath);
diff --git a/src/fileio.c b/src/fileio.c
index 13e2c889020..2590942d42e 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -1111,7 +1111,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
1111 1111
1112 name = make_specified_string (nm, -1, p - nm, multibyte); 1112 name = make_specified_string (nm, -1, p - nm, multibyte);
1113 temp[0] = DRIVE_LETTER (drive); 1113 temp[0] = DRIVE_LETTER (drive);
1114 name = concat2 (build_local_string (temp), name); 1114 name = concat2 (SCOPED_STRING (temp), name);
1115 } 1115 }
1116#ifdef WINDOWSNT 1116#ifdef WINDOWSNT
1117 if (!NILP (Vw32_downcase_file_names)) 1117 if (!NILP (Vw32_downcase_file_names))
@@ -1162,11 +1162,11 @@ filesystem tree, not (expand-file-name ".." dirname). */)
1162 char newdir_utf8[MAX_UTF8_PATH]; 1162 char newdir_utf8[MAX_UTF8_PATH];
1163 1163
1164 filename_from_ansi (newdir, newdir_utf8); 1164 filename_from_ansi (newdir, newdir_utf8);
1165 tem = build_local_string (newdir_utf8); 1165 tem = build_string (newdir_utf8);
1166 } 1166 }
1167 else 1167 else
1168#endif 1168#endif
1169 tem = build_local_string (newdir); 1169 tem = build_string (newdir);
1170 newdirlim = newdir + SBYTES (tem); 1170 newdirlim = newdir + SBYTES (tem);
1171 if (multibyte && !STRING_MULTIBYTE (tem)) 1171 if (multibyte && !STRING_MULTIBYTE (tem))
1172 { 1172 {
@@ -1198,7 +1198,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
1198 /* `getpwnam' may return a unibyte string, which will 1198 /* `getpwnam' may return a unibyte string, which will
1199 bite us since we expect the directory to be 1199 bite us since we expect the directory to be
1200 multibyte. */ 1200 multibyte. */
1201 tem = build_local_string (newdir); 1201 tem = build_string (newdir);
1202 newdirlim = newdir + SBYTES (tem); 1202 newdirlim = newdir + SBYTES (tem);
1203 if (multibyte && !STRING_MULTIBYTE (tem)) 1203 if (multibyte && !STRING_MULTIBYTE (tem))
1204 { 1204 {
@@ -1231,7 +1231,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
1231 adir = NULL; 1231 adir = NULL;
1232 else if (multibyte) 1232 else if (multibyte)
1233 { 1233 {
1234 Lisp_Object tem = build_local_string (adir); 1234 Lisp_Object tem = build_string (adir);
1235 1235
1236 tem = DECODE_FILE (tem); 1236 tem = DECODE_FILE (tem);
1237 newdirlim = adir + SBYTES (tem); 1237 newdirlim = adir + SBYTES (tem);
@@ -1334,7 +1334,7 @@ filesystem tree, not (expand-file-name ".." dirname). */)
1334 getcwd (adir, adir_size); 1334 getcwd (adir, adir_size);
1335 if (multibyte) 1335 if (multibyte)
1336 { 1336 {
1337 Lisp_Object tem = build_local_string (adir); 1337 Lisp_Object tem = build_string (adir);
1338 1338
1339 tem = DECODE_FILE (tem); 1339 tem = DECODE_FILE (tem);
1340 newdirlim = adir + SBYTES (tem); 1340 newdirlim = adir + SBYTES (tem);
@@ -5420,7 +5420,7 @@ auto_save_error (Lisp_Object error_val)
5420 ring_bell (XFRAME (selected_frame)); 5420 ring_bell (XFRAME (selected_frame));
5421 5421
5422 msg = Fformat (3, ((Lisp_Object []) 5422 msg = Fformat (3, ((Lisp_Object [])
5423 { build_local_string ("Auto-saving %s: %s"), 5423 { SCOPED_STRING ("Auto-saving %s: %s"),
5424 BVAR (current_buffer, name), 5424 BVAR (current_buffer, name),
5425 Ferror_message_string (error_val) })); 5425 Ferror_message_string (error_val) }));
5426 GCPRO1 (msg); 5426 GCPRO1 (msg);
diff --git a/src/fns.c b/src/fns.c
index 836a621cd51..abdc56afdb4 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -2726,7 +2726,7 @@ if `last-nonmenu-event' is nil, and `use-dialog-box' is non-nil. */)
2726 } 2726 }
2727 2727
2728 prompt = Fconcat (2, ((Lisp_Object []) 2728 prompt = Fconcat (2, ((Lisp_Object [])
2729 { prompt, build_local_string ("(yes or no) ") })); 2729 { prompt, SCOPED_STRING ("(yes or no) ") }));
2730 GCPRO1 (prompt); 2730 GCPRO1 (prompt);
2731 2731
2732 while (1) 2732 while (1)
diff --git a/src/font.c b/src/font.c
index 673a934f38f..ef48bbdaea6 100644
--- a/src/font.c
+++ b/src/font.c
@@ -1187,12 +1187,12 @@ font_parse_xlfd (char *name, ptrdiff_t len, Lisp_Object font)
1187 { 1187 {
1188 val = prop[XLFD_ENCODING_INDEX]; 1188 val = prop[XLFD_ENCODING_INDEX];
1189 if (! NILP (val)) 1189 if (! NILP (val))
1190 val = concat2 (build_local_string ("*-"), SYMBOL_NAME (val)); 1190 val = concat2 (SCOPED_STRING ("*-"), SYMBOL_NAME (val));
1191 } 1191 }
1192 else if (NILP (prop[XLFD_ENCODING_INDEX])) 1192 else if (NILP (prop[XLFD_ENCODING_INDEX]))
1193 val = concat2 (SYMBOL_NAME (val), build_local_string ("-*")); 1193 val = concat2 (SYMBOL_NAME (val), SCOPED_STRING ("-*"));
1194 else 1194 else
1195 val = concat3 (SYMBOL_NAME (val), build_local_string ("-"), 1195 val = concat3 (SYMBOL_NAME (val), SCOPED_STRING ("-"),
1196 SYMBOL_NAME (prop[XLFD_ENCODING_INDEX])); 1196 SYMBOL_NAME (prop[XLFD_ENCODING_INDEX]));
1197 if (! NILP (val)) 1197 if (! NILP (val))
1198 ASET (font, FONT_REGISTRY_INDEX, Fintern (val, Qnil)); 1198 ASET (font, FONT_REGISTRY_INDEX, Fintern (val, Qnil));
@@ -1790,9 +1790,9 @@ font_parse_family_registry (Lisp_Object family, Lisp_Object registry, Lisp_Objec
1790 if (! p1) 1790 if (! p1)
1791 { 1791 {
1792 if (SDATA (registry)[len - 1] == '*') 1792 if (SDATA (registry)[len - 1] == '*')
1793 registry = concat2 (registry, build_local_string ("-*")); 1793 registry = concat2 (registry, SCOPED_STRING ("-*"));
1794 else 1794 else
1795 registry = concat2 (registry, build_local_string ("*-*")); 1795 registry = concat2 (registry, SCOPED_STRING ("*-*"));
1796 } 1796 }
1797 registry = Fdowncase (registry); 1797 registry = Fdowncase (registry);
1798 ASET (font_spec, FONT_REGISTRY_INDEX, Fintern (registry, Qnil)); 1798 ASET (font_spec, FONT_REGISTRY_INDEX, Fintern (registry, Qnil));
@@ -5019,7 +5019,7 @@ font_add_log (const char *action, Lisp_Object arg, Lisp_Object result)
5019 if (FONTP (arg)) 5019 if (FONTP (arg))
5020 { 5020 {
5021 Lisp_Object tail, elt; 5021 Lisp_Object tail, elt;
5022 Lisp_Object equalstr = build_local_string ("="); 5022 Lisp_Object equalstr = SCOPED_STRING ("=");
5023 5023
5024 val = Ffont_xlfd_name (arg, Qt); 5024 val = Ffont_xlfd_name (arg, Qt);
5025 for (tail = AREF (arg, FONT_EXTRA_INDEX); CONSP (tail); 5025 for (tail = AREF (arg, FONT_EXTRA_INDEX); CONSP (tail);
@@ -5053,7 +5053,7 @@ font_add_log (const char *action, Lisp_Object arg, Lisp_Object result)
5053 val = Ffont_xlfd_name (result, Qt); 5053 val = Ffont_xlfd_name (result, Qt);
5054 if (! FONT_SPEC_P (result)) 5054 if (! FONT_SPEC_P (result))
5055 val = concat3 (SYMBOL_NAME (AREF (result, FONT_TYPE_INDEX)), 5055 val = concat3 (SYMBOL_NAME (AREF (result, FONT_TYPE_INDEX)),
5056 build_local_string (":"), val); 5056 SCOPED_STRING (":"), val);
5057 result = val; 5057 result = val;
5058 } 5058 }
5059 else if (CONSP (result)) 5059 else if (CONSP (result))
diff --git a/src/fontset.c b/src/fontset.c
index 5e18d14bd65..1b750b05b7b 100644
--- a/src/fontset.c
+++ b/src/fontset.c
@@ -1462,7 +1462,7 @@ appended. By default, FONT-SPEC overrides the previous settings. */)
1462 registry = AREF (font_spec, FONT_REGISTRY_INDEX); 1462 registry = AREF (font_spec, FONT_REGISTRY_INDEX);
1463 if (! NILP (registry)) 1463 if (! NILP (registry))
1464 registry = Fdowncase (SYMBOL_NAME (registry)); 1464 registry = Fdowncase (SYMBOL_NAME (registry));
1465 encoding = find_font_encoding (concat3 (family, build_local_string ("-"), 1465 encoding = find_font_encoding (concat3 (family, SCOPED_STRING ("-"),
1466 registry)); 1466 registry));
1467 if (NILP (encoding)) 1467 if (NILP (encoding))
1468 encoding = Qascii; 1468 encoding = Qascii;
diff --git a/src/frame.c b/src/frame.c
index 0eea4f4338a..9bc52f1e88f 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -4149,8 +4149,8 @@ x_get_arg (Display_Info *dpyinfo, Lisp_Object alist, Lisp_Object param,
4149 if (attribute && dpyinfo) 4149 if (attribute && dpyinfo)
4150 { 4150 {
4151 tem = display_x_get_resource 4151 tem = display_x_get_resource
4152 (dpyinfo, build_local_string (attribute), 4152 (dpyinfo, SCOPED_STRING (attribute),
4153 build_local_string (class), Qnil, Qnil); 4153 SCOPED_STRING (class), Qnil, Qnil);
4154 4154
4155 if (NILP (tem)) 4155 if (NILP (tem))
4156 return Qunbound; 4156 return Qunbound;
diff --git a/src/keyboard.c b/src/keyboard.c
index d920ef45f45..37d33a6cdb0 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -566,10 +566,10 @@ echo_add_key (Lisp_Object c)
566 if (XINT (last_char) == '-' && XINT (prev_char) != ' ') 566 if (XINT (last_char) == '-' && XINT (prev_char) != ' ')
567 Faset (echo_string, idx, make_number (' ')); 567 Faset (echo_string, idx, make_number (' '));
568 else 568 else
569 echo_string = concat2 (echo_string, build_local_string (" ")); 569 echo_string = concat2 (echo_string, SCOPED_STRING (" "));
570 } 570 }
571 else if (STRINGP (echo_string) && SCHARS (echo_string) > 0) 571 else if (STRINGP (echo_string) && SCHARS (echo_string) > 0)
572 echo_string = concat2 (echo_string, build_local_string (" ")); 572 echo_string = concat2 (echo_string, SCOPED_STRING (" "));
573 573
574 kset_echo_string 574 kset_echo_string
575 (current_kboard, 575 (current_kboard,
@@ -632,7 +632,7 @@ echo_dash (void)
632 but make it go away when the next character is added. */ 632 but make it go away when the next character is added. */
633 kset_echo_string 633 kset_echo_string
634 (current_kboard, 634 (current_kboard,
635 concat2 (KVAR (current_kboard, echo_string), build_local_string ("-"))); 635 concat2 (KVAR (current_kboard, echo_string), SCOPED_STRING ("-")));
636 echo_now (); 636 echo_now ();
637} 637}
638 638
@@ -1896,7 +1896,7 @@ safe_run_hooks_error (Lisp_Object error, ptrdiff_t nargs, Lisp_Object *args)
1896 hook = args[0]; 1896 hook = args[0];
1897 fun = args[1]; 1897 fun = args[1];
1898 Fmessage (4, ((Lisp_Object []) 1898 Fmessage (4, ((Lisp_Object [])
1899 { build_local_string ("Error in %s (%S): %S"), hook, fun, error })); 1899 { SCOPED_STRING ("Error in %s (%S): %S"), hook, fun, error }));
1900 1900
1901 if (SYMBOLP (hook)) 1901 if (SYMBOLP (hook))
1902 { 1902 {
@@ -7889,7 +7889,7 @@ parse_menu_item (Lisp_Object item, int inmenubar)
7889 /* The previous code preferred :key-sequence to :keys, so we 7889 /* The previous code preferred :key-sequence to :keys, so we
7890 preserve this behavior. */ 7890 preserve this behavior. */
7891 if (STRINGP (keyeq) && !CONSP (keyhint)) 7891 if (STRINGP (keyeq) && !CONSP (keyhint))
7892 keyeq = concat2 (build_local_string (" "), 7892 keyeq = concat2 (SCOPED_STRING (" "),
7893 Fsubstitute_command_keys (keyeq)); 7893 Fsubstitute_command_keys (keyeq));
7894 else 7894 else
7895 { 7895 {
@@ -7933,7 +7933,7 @@ parse_menu_item (Lisp_Object item, int inmenubar)
7933 if (STRINGP (XCDR (prefix))) 7933 if (STRINGP (XCDR (prefix)))
7934 tem = concat2 (tem, XCDR (prefix)); 7934 tem = concat2 (tem, XCDR (prefix));
7935 } 7935 }
7936 keyeq = concat2 (build_local_string (" "), tem); 7936 keyeq = concat2 (SCOPED_STRING (" "), tem);
7937 } 7937 }
7938 else 7938 else
7939 keyeq = Qnil; 7939 keyeq = Qnil;
@@ -8638,9 +8638,9 @@ read_char_minibuf_menu_prompt (int commandflag,
8638 Lisp_Object selected 8638 Lisp_Object selected
8639 = AREF (item_properties, ITEM_PROPERTY_SELECTED); 8639 = AREF (item_properties, ITEM_PROPERTY_SELECTED);
8640 if (EQ (tem, QCradio)) 8640 if (EQ (tem, QCradio))
8641 tem = build_local_string (NILP (selected) ? "(*) " : "( ) "); 8641 tem = SCOPED_STRING (NILP (selected) ? "(*) " : "( ) ");
8642 else 8642 else
8643 tem = build_local_string (NILP (selected) ? "[X] " : "[ ] "); 8643 tem = SCOPED_STRING (NILP (selected) ? "[X] " : "[ ] ");
8644 s = concat2 (tem, s); 8644 s = concat2 (tem, s);
8645 } 8645 }
8646 8646
diff --git a/src/keymap.c b/src/keymap.c
index ed572a5a8c1..368903db5e6 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -1338,7 +1338,7 @@ silly_event_symbol_error (Lisp_Object c)
1338 *p = 0; 1338 *p = 0;
1339 1339
1340 c = reorder_modifiers (c); 1340 c = reorder_modifiers (c);
1341 keystring = concat2 (build_local_string (new_mods), XCDR (assoc)); 1341 keystring = concat2 (SCOPED_STRING (new_mods), XCDR (assoc));
1342 1342
1343 error ("To bind the key %s, use [?%s], not [%s]", 1343 error ("To bind the key %s, use [?%s], not [%s]",
1344 SDATA (SYMBOL_NAME (c)), SDATA (keystring), 1344 SDATA (SYMBOL_NAME (c)), SDATA (keystring),
@@ -2243,7 +2243,7 @@ around function keys and event symbols. */)
2243 if (CONSP (key) && INTEGERP (XCAR (key)) && INTEGERP (XCDR (key))) 2243 if (CONSP (key) && INTEGERP (XCAR (key)) && INTEGERP (XCDR (key)))
2244 /* An interval from a map-char-table. */ 2244 /* An interval from a map-char-table. */
2245 return concat3 (Fsingle_key_description (XCAR (key), no_angles), 2245 return concat3 (Fsingle_key_description (XCAR (key), no_angles),
2246 build_local_string (".."), 2246 SCOPED_STRING (".."),
2247 Fsingle_key_description (XCDR (key), no_angles)); 2247 Fsingle_key_description (XCDR (key), no_angles));
2248 2248
2249 key = EVENT_HEAD (key); 2249 key = EVENT_HEAD (key);
@@ -3441,7 +3441,7 @@ describe_vector (Lisp_Object vector, Lisp_Object prefix, Lisp_Object args,
3441 { 3441 {
3442 Lisp_Object tem; 3442 Lisp_Object tem;
3443 tem = Fkey_description (prefix, Qnil); 3443 tem = Fkey_description (prefix, Qnil);
3444 elt_prefix = concat2 (tem, build_local_string (" ")); 3444 elt_prefix = concat2 (tem, SCOPED_STRING (" "));
3445 } 3445 }
3446 prefix = Qnil; 3446 prefix = Qnil;
3447 } 3447 }
diff --git a/src/lisp.h b/src/lisp.h
index d2cac17fbc7..27751af2f5b 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -282,23 +282,7 @@ error !;
282# endif 282# endif
283#endif 283#endif
284 284
285/* This should work with GCC. Clang has known problems; see 285#ifdef HAVE_STRUCT_ATTRIBUTE_ALIGNED
286 http://lists.gnu.org/archive/html/emacs-devel/2014-09/msg00506.html. */
287#ifndef USE_STACK_LISP_OBJECTS
288# if defined __GNUC__ && !defined __clang__
289 /* 32-bit MinGW builds need at least GCC 4.2 to support this. */
290# if defined __MINGW32__ && !defined _W64 \
291 && __GNUC__ + (__GNUC_MINOR__ > 1) < 5
292# define USE_STACK_LISP_OBJECTS false
293# else /* !(__MINGW32__ && __GNUC__ < 4.2) */
294# define USE_STACK_LISP_OBJECTS true
295# endif
296# else
297# define USE_STACK_LISP_OBJECTS false
298# endif
299#endif
300
301#if defined HAVE_STRUCT_ATTRIBUTE_ALIGNED && USE_STACK_LISP_OBJECTS
302# define GCALIGNED __attribute__ ((aligned (GCALIGNMENT))) 286# define GCALIGNED __attribute__ ((aligned (GCALIGNMENT)))
303#else 287#else
304# define GCALIGNED /* empty */ 288# define GCALIGNED /* empty */
@@ -1088,7 +1072,7 @@ CDR_SAFE (Lisp_Object c)
1088 1072
1089/* In a string or vector, the sign bit of the `size' is the gc mark bit. */ 1073/* In a string or vector, the sign bit of the `size' is the gc mark bit. */
1090 1074
1091struct Lisp_String 1075struct GCALIGNED Lisp_String
1092 { 1076 {
1093 ptrdiff_t size; 1077 ptrdiff_t size;
1094 ptrdiff_t size_byte; 1078 ptrdiff_t size_byte;
@@ -4598,27 +4582,26 @@ lisp_word_count (ptrdiff_t nbytes)
4598 4582
4599 4583
4600/* If USE_STACK_LISP_OBJECTS, define macros that and functions that allocate 4584/* If USE_STACK_LISP_OBJECTS, define macros that and functions that allocate
4601 block-scoped conses and function-scoped strings. These objects are not 4585 block-scoped conses and strings. These objects are not
4602 managed by the garbage collector, so they are dangerous: passing them 4586 managed by the garbage collector, so they are dangerous: passing them
4603 out of their scope (e.g., to user code) results in undefined behavior. 4587 out of their scope (e.g., to user code) results in undefined behavior.
4604 Conversely, they have better performance because GC is not involved. 4588 Conversely, they have better performance because GC is not involved.
4605 4589
4606 This feature is experimental and requires careful debugging. It's enabled 4590 This feature is experimental and requires careful debugging.
4607 by default if GCC or a compiler that mimics GCC well (like Intel C/C++) is 4591 Build with CPPFLAGS='-DUSE_STACK_LISP_OBJECTS=0' to disable it. */
4608 used, except clang (see notice above). For other compilers, brave users can
4609 compile with CPPFLAGS='-DUSE_STACK_LISP_OBJECTS=1' to get into the game.
4610 Note that this feature requires GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS. */
4611 4592
4612#ifdef GCALIGNED 4593#ifndef USE_STACK_LISP_OBJECTS
4613 4594# define USE_STACK_LISP_OBJECTS true
4614/* No tricks if struct Lisp_Cons is always aligned. */ 4595#endif
4615 4596
4616# define SCOPED_CONS_INITIALIZER(a, b) &((struct Lisp_Cons) { a, { b } }) 4597/* USE_STACK_LISP_OBJECTS requires GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS. */
4617 4598
4618#else /* not GCALIGNED */ 4599#if GC_MARK_STACK != GC_MAKE_GCPROS_NOOPS
4600# undef USE_STACK_LISP_OBJECTS
4601# define USE_STACK_LISP_OBJECTS false
4602#endif
4619 4603
4620/* A struct Lisp_Cons inside a union that is no larger and may be 4604/* Struct inside unions that are typically no larger and aligned enough. */
4621 better-aligned. */
4622 4605
4623union Aligned_Cons 4606union Aligned_Cons
4624{ 4607{
@@ -4626,88 +4609,61 @@ union Aligned_Cons
4626 double d; intmax_t i; void *p; 4609 double d; intmax_t i; void *p;
4627}; 4610};
4628 4611
4629verify (alignof (union Aligned_Cons) % GCALIGNMENT == 0); 4612union Aligned_String
4630verify (sizeof (struct Lisp_Cons) == sizeof (union Aligned_Cons)); 4613{
4631 4614 struct Lisp_String s;
4632# define SCOPED_CONS_INITIALIZER(a, b) \ 4615 double d; intmax_t i; void *p;
4633 &((union Aligned_Cons) { { a, { b } } }.s) 4616};
4634
4635#endif /* GCALIGNED */
4636
4637/* Basic stack-based cons allocation. */
4638
4639#if USE_STACK_LISP_OBJECTS
4640# define scoped_cons(a, b) \
4641 make_lisp_ptr (SCOPED_CONS_INITIALIZER (a, b), Lisp_Cons)
4642# define scoped_list1(a) scoped_cons (a, Qnil)
4643# define scoped_list2(a, b) scoped_cons (a, scoped_list1 (b))
4644# define scoped_list3(a, b, c) scoped_cons (a, scoped_list2 (b, c))
4645# define scoped_list4(a, b, c, d) scoped_cons (a, scoped_list3 (b, c, d))
4646#else
4647# define scoped_cons(a, b) Fcons (a, b)
4648# define scoped_list1(a) list1 (a)
4649# define scoped_list2(a, b) list2 (a, b)
4650# define scoped_list3(a, b, c) list3 (a, b, c)
4651# define scoped_list4(a, b, c, d) list4 (a, b, c, d)
4652#endif
4653 4617
4654/* On-stack string allocation requires __builtin_constant_p, statement 4618/* True for stack-based cons and string implementations. */
4655 expressions and GCALIGNMENT-aligned alloca. All from the above is
4656 assumed for GCC. At least for clang < 3.6, alloca isn't properly
4657 aligned in some cases. In the absence of solid information, play
4658 it safe for other non-GCC compilers. */
4659 4619
4660#if USE_STACK_LISP_OBJECTS && __GNUC__ && !__clang__ 4620enum
4621 {
4622 USE_STACK_CONS = (USE_STACK_LISP_OBJECTS
4623 && alignof (union Aligned_Cons) % GCALIGNMENT == 0),
4624 USE_STACK_STRING = (USE_STACK_LISP_OBJECTS
4625 && alignof (union Aligned_String) % GCALIGNMENT == 0)
4626 };
4661 4627
4662/* Used to check whether stack-allocated strings are ASCII-only. */ 4628/* Build a stack-based Lisp cons or short list if possible, a GC-based
4629 one otherwise. The resulting object should not be modified or made
4630 visible to user code. */
4631
4632#define scoped_cons(a, b) \
4633 (USE_STACK_CONS \
4634 ? make_lisp_ptr (&(union Aligned_Cons) { { a, { b } } }.s, Lisp_Cons) \
4635 : Fcons (a, b))
4636#define scoped_list1(a) \
4637 (USE_STACK_CONS ? scoped_cons (a, Qnil) : list1 (a))
4638#define scoped_list2(a, b) \
4639 (USE_STACK_CONS ? scoped_cons (a, scoped_list1 (b)) : list2 (a,b))
4640#define scoped_list3(a, b, c) \
4641 (USE_STACK_CONS ? scoped_cons (a, scoped_list2 (b, c)) : list3 (a, b, c))
4642#define scoped_list4(a, b, c, d) \
4643 (USE_STACK_CONS \
4644 ? scoped_cons (a, scoped_list3 (b, c, d)) : \
4645 list4 (a, b, c, d))
4646
4647/* Check whether stack-allocated strings are ASCII-only. */
4663 4648
4664#ifdef ENABLE_CHECKING 4649#ifdef ENABLE_CHECKING
4665extern const char * verify_ascii (const char *); 4650extern const char *verify_ascii (const char *);
4666#else 4651#else
4667#define verify_ascii(str) (str) 4652# define verify_ascii(str) (str)
4668#endif 4653#endif
4669 4654
4670/* Return number of bytes needed for Lisp string of length NBYTES. */ 4655/* Build a stack-based Lisp string from STR if possible, a GC-based
4671 4656 one if not. STR is not necessarily copied and should contain only
4672INLINE ptrdiff_t 4657 ASCII characters. The resulting Lisp string should not be modified
4673lisp_string_size (ptrdiff_t nbytes) 4658 or made visible to user code. */
4674{ 4659
4675 return sizeof (struct Lisp_String) + nbytes + 1; 4660#define SCOPED_STRING(str) \
4676} 4661 (USE_STACK_STRING \
4677 4662 ? (make_lisp_ptr \
4678/* Return function-scoped unibyte Lisp string with contents STR of length 4663 ((&(union Aligned_String) \
4679 NBYTES and memory footprint of MEMSIZE bytes if the latter doesn't exceed 4664 { { strlen (str), -1, 0, (unsigned char *) verify_ascii (str) } }.s), \
4680 MAX_ALLOCA, abort otherwise. */ 4665 Lisp_String)) \
4681 4666 : build_string (verify_ascii (str)))
4682# define make_local_string(str, memsize, nbytes) \
4683 ((memsize < MAX_ALLOCA) \
4684 ? ({ struct Lisp_String *s_ = alloca (memsize); \
4685 s_->data = (unsigned char *) (s_ + 1); \
4686 memcpy (s_->data, verify_ascii (str), nbytes + 1); \
4687 s_->size = nbytes, s_->size_byte = -1; \
4688 s_->intervals = NULL; \
4689 make_lisp_ptr (s_, Lisp_String); }) \
4690 : (emacs_abort (), Qnil))
4691
4692/* If STR is a compile-time string constant, build function-scoped Lisp string
4693 from it, fall back to regular Lisp string otherwise. We assume compile-time
4694 string constants never exceeds MAX_ALLOCA - sizeof (Lisp_String) - 1. */
4695
4696# define build_local_string(str) \
4697 (__builtin_constant_p (str) \
4698 ? make_local_string \
4699 (str, lisp_string_size (strlen (str)), strlen (str)) \
4700 : build_string (str))
4701
4702#else /* not USE_STACK_LISP_OBJECTS && __GNUC__ && !__clang__ */
4703
4704INLINE Lisp_Object
4705build_local_string (const char *str)
4706{
4707 return build_string (str);
4708}
4709
4710#endif /* not USE_STACK_LISP_OBJECTS && __GNUC__ && !__clang__ */
4711 4667
4712/* Loop over all tails of a list, checking for cycles. 4668/* Loop over all tails of a list, checking for cycles.
4713 FIXME: Make tortoise and n internal declarations. 4669 FIXME: Make tortoise and n internal declarations.
diff --git a/src/lread.c b/src/lread.c
index b6f259f1a95..799635e3c83 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -970,7 +970,7 @@ load_warn_old_style_backquotes (Lisp_Object file)
970{ 970{
971 if (!NILP (Vold_style_backquotes)) 971 if (!NILP (Vold_style_backquotes))
972 Fmessage (2, ((Lisp_Object []) 972 Fmessage (2, ((Lisp_Object [])
973 { build_local_string ("Loading `%s': old-style backquotes detected!"), 973 { SCOPED_STRING ("Loading `%s': old-style backquotes detected!"),
974 file })); 974 file }));
975} 975}
976 976
@@ -3678,7 +3678,7 @@ read_list (bool flag, Lisp_Object readcharfun)
3678 in the installed Lisp directory. 3678 in the installed Lisp directory.
3679 We don't use Fexpand_file_name because that would make 3679 We don't use Fexpand_file_name because that would make
3680 the directory absolute now. */ 3680 the directory absolute now. */
3681 elt = concat2 (build_local_string ("../lisp/"), 3681 elt = concat2 (SCOPED_STRING ("../lisp/"),
3682 Ffile_name_nondirectory (elt)); 3682 Ffile_name_nondirectory (elt));
3683 } 3683 }
3684 else if (EQ (elt, Vload_file_name) 3684 else if (EQ (elt, Vload_file_name)
diff --git a/src/menu.c b/src/menu.c
index ea8da7a9d62..e63b21f0e08 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -354,7 +354,7 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
354 front of them. */ 354 front of them. */
355 if (!have_boxes ()) 355 if (!have_boxes ())
356 { 356 {
357 Lisp_Object prefix = Qnil; 357 char const *prefix = 0;
358 Lisp_Object type = AREF (item_properties, ITEM_PROPERTY_TYPE); 358 Lisp_Object type = AREF (item_properties, ITEM_PROPERTY_TYPE);
359 if (!NILP (type)) 359 if (!NILP (type))
360 { 360 {
@@ -390,7 +390,7 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
390 if (!submenu && SREF (tem, 0) != '\0' 390 if (!submenu && SREF (tem, 0) != '\0'
391 && SREF (tem, 0) != '-') 391 && SREF (tem, 0) != '-')
392 ASET (menu_items, idx + MENU_ITEMS_ITEM_NAME, 392 ASET (menu_items, idx + MENU_ITEMS_ITEM_NAME,
393 concat2 (build_local_string (" "), tem)); 393 concat2 (SCOPED_STRING (" "), tem));
394 idx += MENU_ITEMS_ITEM_LENGTH; 394 idx += MENU_ITEMS_ITEM_LENGTH;
395 } 395 }
396 } 396 }
@@ -399,24 +399,24 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
399 399
400 /* Calculate prefix, if any, for this item. */ 400 /* Calculate prefix, if any, for this item. */
401 if (EQ (type, QCtoggle)) 401 if (EQ (type, QCtoggle))
402 prefix = build_local_string (NILP (selected) ? "[ ] " : "[X] "); 402 prefix = NILP (selected) ? "[ ] " : "[X] ";
403 else if (EQ (type, QCradio)) 403 else if (EQ (type, QCradio))
404 prefix = build_local_string (NILP (selected) ? "( ) " : "(*) "); 404 prefix = NILP (selected) ? "( ) " : "(*) ";
405 } 405 }
406 /* Not a button. If we have earlier buttons, then we need a prefix. */ 406 /* Not a button. If we have earlier buttons, then we need a prefix. */
407 else if (!skp->notbuttons && SREF (item_string, 0) != '\0' 407 else if (!skp->notbuttons && SREF (item_string, 0) != '\0'
408 && SREF (item_string, 0) != '-') 408 && SREF (item_string, 0) != '-')
409 prefix = build_local_string (" "); 409 prefix = " ";
410 410
411 if (!NILP (prefix)) 411 if (prefix)
412 item_string = concat2 (prefix, item_string); 412 item_string = concat2 (SCOPED_STRING (prefix), item_string);
413 } 413 }
414 414
415 if ((FRAME_TERMCAP_P (XFRAME (Vmenu_updating_frame)) 415 if ((FRAME_TERMCAP_P (XFRAME (Vmenu_updating_frame))
416 || FRAME_MSDOS_P (XFRAME (Vmenu_updating_frame))) 416 || FRAME_MSDOS_P (XFRAME (Vmenu_updating_frame)))
417 && !NILP (map)) 417 && !NILP (map))
418 /* Indicate visually that this is a submenu. */ 418 /* Indicate visually that this is a submenu. */
419 item_string = concat2 (item_string, build_local_string (" >")); 419 item_string = concat2 (item_string, SCOPED_STRING (" >"));
420 420
421 push_menu_item (item_string, enabled, key, 421 push_menu_item (item_string, enabled, key,
422 AREF (item_properties, ITEM_PROPERTY_DEF), 422 AREF (item_properties, ITEM_PROPERTY_DEF),
diff --git a/src/minibuf.c b/src/minibuf.c
index b5e7e4cd76e..ea525ba0f25 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -1158,7 +1158,7 @@ function, instead of the usual behavior. */)
1158 } 1158 }
1159 1159
1160 prompt = Fformat (3, ((Lisp_Object []) 1160 prompt = Fformat (3, ((Lisp_Object [])
1161 { build_local_string ("%s (default %s): "), 1161 { SCOPED_STRING ("%s (default %s): "),
1162 prompt, CONSP (def) ? XCAR (def) : def })); 1162 prompt, CONSP (def) ? XCAR (def) : def }));
1163 } 1163 }
1164 1164
diff --git a/src/process.c b/src/process.c
index f6484d0370e..6d059af9cc8 100644
--- a/src/process.c
+++ b/src/process.c
@@ -620,7 +620,7 @@ status_message (struct Lisp_Process *p)
620 if (c1 != c2) 620 if (c1 != c2)
621 Faset (string, make_number (0), make_number (c2)); 621 Faset (string, make_number (0), make_number (c2));
622 } 622 }
623 string2 = build_local_string (coredump ? " (core dumped)\n" : "\n"); 623 string2 = SCOPED_STRING (coredump ? " (core dumped)\n" : "\n");
624 return concat2 (string, string2); 624 return concat2 (string, string2);
625 } 625 }
626 else if (EQ (symbol, Qexit)) 626 else if (EQ (symbol, Qexit))
@@ -630,15 +630,15 @@ status_message (struct Lisp_Process *p)
630 if (code == 0) 630 if (code == 0)
631 return build_string ("finished\n"); 631 return build_string ("finished\n");
632 string = Fnumber_to_string (make_number (code)); 632 string = Fnumber_to_string (make_number (code));
633 string2 = build_local_string (coredump ? " (core dumped)\n" : "\n"); 633 string2 = SCOPED_STRING (coredump ? " (core dumped)\n" : "\n");
634 return concat3 (build_local_string ("exited abnormally with code "), 634 return concat3 (SCOPED_STRING ("exited abnormally with code "),
635 string, string2); 635 string, string2);
636 } 636 }
637 else if (EQ (symbol, Qfailed)) 637 else if (EQ (symbol, Qfailed))
638 { 638 {
639 string = Fnumber_to_string (make_number (code)); 639 string = Fnumber_to_string (make_number (code));
640 string2 = build_local_string ("\n"); 640 string2 = SCOPED_STRING ("\n");
641 return concat3 (build_local_string ("failed with code "), 641 return concat3 (SCOPED_STRING ("failed with code "),
642 string, string2); 642 string, string2);
643 } 643 }
644 else 644 else
@@ -1302,30 +1302,33 @@ Returns nil if format of ADDRESS is invalid. */)
1302 ptrdiff_t size = p->header.size; 1302 ptrdiff_t size = p->header.size;
1303 Lisp_Object args[10]; 1303 Lisp_Object args[10];
1304 int nargs, i; 1304 int nargs, i;
1305 char const *format;
1305 1306
1306 if (size == 4 || (size == 5 && !NILP (omit_port))) 1307 if (size == 4 || (size == 5 && !NILP (omit_port)))
1307 { 1308 {
1308 args[0] = build_local_string ("%d.%d.%d.%d"); 1309 format = "%d.%d.%d.%d";
1309 nargs = 4; 1310 nargs = 4;
1310 } 1311 }
1311 else if (size == 5) 1312 else if (size == 5)
1312 { 1313 {
1313 args[0] = build_local_string ("%d.%d.%d.%d:%d"); 1314 format = "%d.%d.%d.%d:%d";
1314 nargs = 5; 1315 nargs = 5;
1315 } 1316 }
1316 else if (size == 8 || (size == 9 && !NILP (omit_port))) 1317 else if (size == 8 || (size == 9 && !NILP (omit_port)))
1317 { 1318 {
1318 args[0] = build_local_string ("%x:%x:%x:%x:%x:%x:%x:%x"); 1319 format = "%x:%x:%x:%x:%x:%x:%x:%x";
1319 nargs = 8; 1320 nargs = 8;
1320 } 1321 }
1321 else if (size == 9) 1322 else if (size == 9)
1322 { 1323 {
1323 args[0] = build_local_string ("[%x:%x:%x:%x:%x:%x:%x:%x]:%d"); 1324 format = "[%x:%x:%x:%x:%x:%x:%x:%x]:%d";
1324 nargs = 9; 1325 nargs = 9;
1325 } 1326 }
1326 else 1327 else
1327 return Qnil; 1328 return Qnil;
1328 1329
1330 args[0] = SCOPED_STRING (format);
1331
1329 for (i = 0; i < nargs; i++) 1332 for (i = 0; i < nargs; i++)
1330 { 1333 {
1331 if (! RANGED_INTEGERP (0, p->contents[i], 65535)) 1334 if (! RANGED_INTEGERP (0, p->contents[i], 65535))
@@ -1344,7 +1347,7 @@ Returns nil if format of ADDRESS is invalid. */)
1344 1347
1345 if (CONSP (address)) 1348 if (CONSP (address))
1346 return Fformat (2, ((Lisp_Object []) 1349 return Fformat (2, ((Lisp_Object [])
1347 { build_local_string ("<Family %d>"), Fcar (address) })); 1350 { SCOPED_STRING ("<Family %d>"), Fcar (address) }));
1348 1351
1349 return Qnil; 1352 return Qnil;
1350} 1353}
@@ -4060,11 +4063,11 @@ server_accept_connection (Lisp_Object server, int channel)
4060 unsigned char *ip = (unsigned char *)&saddr.in.sin_addr.s_addr; 4063 unsigned char *ip = (unsigned char *)&saddr.in.sin_addr.s_addr;
4061 4064
4062 host = Fformat (5, ((Lisp_Object []) 4065 host = Fformat (5, ((Lisp_Object [])
4063 { build_local_string ("%d.%d.%d.%d"), make_number (ip[0]), 4066 { SCOPED_STRING ("%d.%d.%d.%d"), make_number (ip[0]),
4064 make_number (ip[1]), make_number (ip[2]), make_number (ip[3]) })); 4067 make_number (ip[1]), make_number (ip[2]), make_number (ip[3]) }));
4065 service = make_number (ntohs (saddr.in.sin_port)); 4068 service = make_number (ntohs (saddr.in.sin_port));
4066 caller = Fformat (3, ((Lisp_Object []) 4069 caller = Fformat (3, ((Lisp_Object [])
4067 { build_local_string (" <%s:%d>"), host, service })); 4070 { SCOPED_STRING (" <%s:%d>"), host, service }));
4068 } 4071 }
4069 break; 4072 break;
4070 4073
@@ -4075,13 +4078,13 @@ server_accept_connection (Lisp_Object server, int channel)
4075 uint16_t *ip6 = (uint16_t *)&saddr.in6.sin6_addr; 4078 uint16_t *ip6 = (uint16_t *)&saddr.in6.sin6_addr;
4076 int i; 4079 int i;
4077 4080
4078 args[0] = build_local_string ("%x:%x:%x:%x:%x:%x:%x:%x"); 4081 args[0] = SCOPED_STRING ("%x:%x:%x:%x:%x:%x:%x:%x");
4079 for (i = 0; i < 8; i++) 4082 for (i = 0; i < 8; i++)
4080 args[i + 1] = make_number (ntohs (ip6[i])); 4083 args[i + 1] = make_number (ntohs (ip6[i]));
4081 host = Fformat (9, args); 4084 host = Fformat (9, args);
4082 service = make_number (ntohs (saddr.in.sin_port)); 4085 service = make_number (ntohs (saddr.in.sin_port));
4083 caller = Fformat (3, ((Lisp_Object []) 4086 caller = Fformat (3, ((Lisp_Object [])
4084 { build_local_string (" <[%s]:%d>"), host, service })); 4087 { SCOPED_STRING (" <[%s]:%d>"), host, service }));
4085 } 4088 }
4086 break; 4089 break;
4087#endif 4090#endif
@@ -4092,7 +4095,7 @@ server_accept_connection (Lisp_Object server, int channel)
4092 default: 4095 default:
4093 caller = Fnumber_to_string (make_number (connect_counter)); 4096 caller = Fnumber_to_string (make_number (connect_counter));
4094 caller = concat3 4097 caller = concat3
4095 (build_local_string (" <"), caller, build_local_string (">")); 4098 (SCOPED_STRING (" <"), caller, SCOPED_STRING (">"));
4096 break; 4099 break;
4097 } 4100 }
4098 4101
@@ -4191,14 +4194,14 @@ server_accept_connection (Lisp_Object server, int channel)
4191 4194
4192 if (!NILP (ps->log)) 4195 if (!NILP (ps->log))
4193 call3 (ps->log, server, proc, 4196 call3 (ps->log, server, proc,
4194 concat3 (build_local_string ("accept from "), 4197 concat3 (SCOPED_STRING ("accept from "),
4195 (STRINGP (host) ? host : build_local_string ("-")), 4198 (STRINGP (host) ? host : SCOPED_STRING ("-")),
4196 build_local_string ("\n"))); 4199 SCOPED_STRING ("\n")));
4197 4200
4198 exec_sentinel (proc, 4201 exec_sentinel (proc,
4199 concat3 (build_local_string ("open from "), 4202 concat3 (SCOPED_STRING ("open from "),
4200 (STRINGP (host) ? host : build_local_string ("-")), 4203 (STRINGP (host) ? host : SCOPED_STRING ("-")),
4201 build_local_string ("\n"))); 4204 SCOPED_STRING ("\n")));
4202} 4205}
4203 4206
4204/* This variable is different from waiting_for_input in keyboard.c. 4207/* This variable is different from waiting_for_input in keyboard.c.
diff --git a/src/xdisp.c b/src/xdisp.c
index f5043c3866a..bf620085727 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -20928,7 +20928,7 @@ See also `bidi-paragraph-direction'. */)
20928 the previous non-empty line. */ 20928 the previous non-empty line. */
20929 if (pos >= ZV && pos > BEGV) 20929 if (pos >= ZV && pos > BEGV)
20930 DEC_BOTH (pos, bytepos); 20930 DEC_BOTH (pos, bytepos);
20931 if (fast_looking_at (build_local_string ("[\f\t ]*\n"), 20931 if (fast_looking_at (SCOPED_STRING ("[\f\t ]*\n"),
20932 pos, bytepos, ZV, ZV_BYTE, Qnil) > 0) 20932 pos, bytepos, ZV, ZV_BYTE, Qnil) > 0)
20933 { 20933 {
20934 while ((c = FETCH_BYTE (bytepos)) == '\n' 20934 while ((c = FETCH_BYTE (bytepos)) == '\n'
diff --git a/src/xfns.c b/src/xfns.c
index 3b094554577..f474e88ba7e 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -1570,11 +1570,9 @@ x_default_scroll_bar_color_parameter (struct frame *f,
1570 /* See if an X resource for the scroll bar color has been 1570 /* See if an X resource for the scroll bar color has been
1571 specified. */ 1571 specified. */
1572 tem = display_x_get_resource 1572 tem = display_x_get_resource
1573 (dpyinfo, build_local_string (foreground_p 1573 (dpyinfo, SCOPED_STRING (foreground_p ? "foreground" : "background"),
1574 ? "foreground"
1575 : "background"),
1576 empty_unibyte_string, 1574 empty_unibyte_string,
1577 build_local_string ("verticalScrollBar"), 1575 SCOPED_STRING ("verticalScrollBar"),
1578 empty_unibyte_string); 1576 empty_unibyte_string);
1579 if (!STRINGP (tem)) 1577 if (!STRINGP (tem))
1580 { 1578 {
@@ -4275,8 +4273,8 @@ select_visual (struct x_display_info *dpyinfo)
4275 4273
4276 /* See if a visual is specified. */ 4274 /* See if a visual is specified. */
4277 Lisp_Object value = display_x_get_resource 4275 Lisp_Object value = display_x_get_resource
4278 (dpyinfo, build_local_string ("visualClass"), 4276 (dpyinfo, SCOPED_STRING ("visualClass"),
4279 build_local_string ("VisualClass"), Qnil, Qnil); 4277 SCOPED_STRING ("VisualClass"), Qnil, Qnil);
4280 4278
4281 if (STRINGP (value)) 4279 if (STRINGP (value))
4282 { 4280 {
diff --git a/src/xselect.c b/src/xselect.c
index 0bc7fbc204a..d90d056e960 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -2160,7 +2160,7 @@ static Lisp_Object
2160x_clipboard_manager_error_1 (Lisp_Object err) 2160x_clipboard_manager_error_1 (Lisp_Object err)
2161{ 2161{
2162 Fmessage (2, ((Lisp_Object []) 2162 Fmessage (2, ((Lisp_Object [])
2163 { build_local_string ("X clipboard manager error: %s\n\ 2163 { SCOPED_STRING ("X clipboard manager error: %s\n\
2164If the problem persists, set `x-select-enable-clipboard-manager' to nil."), 2164If the problem persists, set `x-select-enable-clipboard-manager' to nil."),
2165 CAR (CDR (err)) })); 2165 CAR (CDR (err)) }));
2166 return Qnil; 2166 return Qnil;
@@ -2230,7 +2230,7 @@ x_clipboard_manager_save_all (void)
2230 if (FRAME_LIVE_P (XFRAME (local_frame))) 2230 if (FRAME_LIVE_P (XFRAME (local_frame)))
2231 { 2231 {
2232 Fmessage (1, ((Lisp_Object []) 2232 Fmessage (1, ((Lisp_Object [])
2233 { build_local_string 2233 { SCOPED_STRING
2234 ("Saving clipboard to X clipboard manager...") })); 2234 ("Saving clipboard to X clipboard manager...") }));
2235 internal_condition_case_1 (x_clipboard_manager_save, local_frame, 2235 internal_condition_case_1 (x_clipboard_manager_save, local_frame,
2236 Qt, x_clipboard_manager_error_2); 2236 Qt, x_clipboard_manager_error_2);
diff --git a/src/xterm.c b/src/xterm.c
index 8d52b2a2815..8a0e28a2e1a 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -10937,8 +10937,8 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
10937 { 10937 {
10938 Lisp_Object value; 10938 Lisp_Object value;
10939 value = display_x_get_resource 10939 value = display_x_get_resource
10940 (dpyinfo, build_local_string ("privateColormap"), 10940 (dpyinfo, SCOPED_STRING ("privateColormap"),
10941 build_local_string ("PrivateColormap"), Qnil, Qnil); 10941 SCOPED_STRING ("PrivateColormap"), Qnil, Qnil);
10942 if (STRINGP (value) 10942 if (STRINGP (value)
10943 && (!strcmp (SSDATA (value), "true") 10943 && (!strcmp (SSDATA (value), "true")
10944 || !strcmp (SSDATA (value), "on"))) 10944 || !strcmp (SSDATA (value), "on")))
@@ -11146,8 +11146,8 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
11146 for debugging X code. */ 11146 for debugging X code. */
11147 { 11147 {
11148 Lisp_Object value = display_x_get_resource 11148 Lisp_Object value = display_x_get_resource
11149 (dpyinfo, build_local_string ("synchronous"), 11149 (dpyinfo, SCOPED_STRING ("synchronous"),
11150 build_local_string ("Synchronous"), Qnil, Qnil); 11150 SCOPED_STRING ("Synchronous"), Qnil, Qnil);
11151 if (STRINGP (value) 11151 if (STRINGP (value)
11152 && (!strcmp (SSDATA (value), "true") 11152 && (!strcmp (SSDATA (value), "true")
11153 || !strcmp (SSDATA (value), "on"))) 11153 || !strcmp (SSDATA (value), "on")))
@@ -11156,8 +11156,8 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
11156 11156
11157 { 11157 {
11158 Lisp_Object value = display_x_get_resource 11158 Lisp_Object value = display_x_get_resource
11159 (dpyinfo, build_local_string ("useXIM"), 11159 (dpyinfo, SCOPED_STRING ("useXIM"),
11160 build_local_string ("UseXIM"), Qnil, Qnil); 11160 SCOPED_STRING ("UseXIM"), Qnil, Qnil);
11161#ifdef USE_XIM 11161#ifdef USE_XIM
11162 if (STRINGP (value) 11162 if (STRINGP (value)
11163 && (!strcmp (SSDATA (value), "false") 11163 && (!strcmp (SSDATA (value), "false")