summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2020-04-17 07:57:25 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2020-04-17 09:17:35 -0700
commit3e46a2315f1a999f5811f57a60a2a55f95d8fbb0 (patch)
tree64e35b78bb77f3eba5148650fb7a98bbda7f14d6
parent7f1dae114dffbf4bdec60e38ada4eb0673cfb4e2 (diff)
downloademacs-3e46a2315f1a999f5811f57a60a2a55f95d8fbb0.tar.gz
Prefer inline functions in character.h
In character.h, replace macros with inline functions or enums when this is easy. This improves maintainability and on my platform (Fedora 31 x86-64, gcc -O2) improved CPU performance very slightly (0.3%) on ‘make compile-always’. * src/buffer.h (SANE_TAB_WIDTH, CHARACTER_WIDTH): Move here from character.h, and make them inline functions. Tune CHARACTER_WIDTH so that ASCII_CHAR_WIDTH is no longer needed. (sanitize_tab_width, sanitize_char_width): Move here from character.h. * src/character.h (MAX_CHAR, MAX_UNICODE_CHAR, MAX_1_BYTE_CHAR) (MAX_2_BYTE_CHAR, MAX_3_BYTE_CHAR, MAX_4_BYTE_CHAR) (MAX_5_BYTE_CHAR, MIN_MULTIBYTE_LEADING_CODE) (MAX_MULTIBYTE_LEADING_CODE, MAX_MULTIBYTE_LENGTH): Now enum constants instead of macros. * src/character.h (CHAR_BYTES): Redo to avoid conditional branches. (CHAR_BYTE8_P, BYTE8_TO_CHAR, UNIBYTE_TO_CHAR, CHAR_TO_BYTE8) (CHAR_TO_BYTE_SAFE, CHAR_BYTE8_HEAD_P, CHARACTERP) (CHECK_CHARACTER, CHECK_CHARACTER_CAR, CHECK_CHARACTER_CDR) (CHAR_PRINTABLE_P, CHAR_BYTES, CHAR_LEADING_CODE, BYTE8_STRING) (LEADING_CODE_P, TRAILING_CODE_P, CHAR_HEAD_P) (BYTES_BY_CHAR_HEAD): Now inline functions instead of macros. (ASCII_CHAR_WIDTH): Remove; no longer used. * src/conf_post.h (ATTRIBUTE_PURE): New macro. * src/lisp.h (char_table_ref): Use it, for better inlining. * src/fns.c (base64_decode_1): Add now-necessary casts.
-rw-r--r--src/buffer.h39
-rw-r--r--src/character.h337
-rw-r--r--src/conf_post.h1
-rw-r--r--src/fns.c6
-rw-r--r--src/lisp.h2
5 files changed, 224 insertions, 161 deletions
diff --git a/src/buffer.h b/src/buffer.h
index abb1294d038..9875b8a447b 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -1523,6 +1523,45 @@ lowercasep (int c)
return !uppercasep (c) && upcase (c) != c;
}
+/* Return a non-outlandish value for the tab width. */
+
+INLINE int
+sanitize_tab_width (Lisp_Object width)
+{
+ return (FIXNUMP (width) && 0 < XFIXNUM (width) && XFIXNUM (width) <= 1000
+ ? XFIXNUM (width) : 8);
+}
+
+INLINE int
+SANE_TAB_WIDTH (struct buffer *buf)
+{
+ return sanitize_tab_width (BVAR (buf, tab_width));
+}
+
+/* Return a non-outlandish value for a character width. */
+
+INLINE int
+sanitize_char_width (EMACS_INT width)
+{
+ return 0 <= width && width <= 1000 ? width : 1000;
+}
+
+/* Return the width of character C. The width is measured by how many
+ columns C will occupy on the screen when displayed in the current
+ buffer. The name CHARACTER_WIDTH avoids a collision with <limits.h>
+ CHAR_WIDTH. */
+
+INLINE int
+CHARACTER_WIDTH (int c)
+{
+ return (0x20 <= c && c < 0x7f ? 1
+ : 0x7f < c ? (sanitize_char_width
+ (XFIXNUM (CHAR_TABLE_REF (Vchar_width_table, c))))
+ : c == '\t' ? SANE_TAB_WIDTH (current_buffer)
+ : c == '\n' ? 0
+ : !NILP (BVAR (current_buffer, ctl_arrow)) ? 2 : 4);
+}
+
INLINE_HEADER_END
#endif /* EMACS_BUFFER_H */
diff --git a/src/character.h b/src/character.h
index 7639b018cb0..d4bc718af72 100644
--- a/src/character.h
+++ b/src/character.h
@@ -43,23 +43,23 @@ INLINE_HEADER_BEGIN
*/
/* Maximum character code ((1 << CHARACTERBITS) - 1). */
-#define MAX_CHAR 0x3FFFFF
+enum { MAX_CHAR = 0x3FFFFF };
/* Maximum Unicode character code. */
-#define MAX_UNICODE_CHAR 0x10FFFF
+enum { MAX_UNICODE_CHAR = 0x10FFFF };
/* Maximum N-byte character codes. */
-#define MAX_1_BYTE_CHAR 0x7F
-#define MAX_2_BYTE_CHAR 0x7FF
-#define MAX_3_BYTE_CHAR 0xFFFF
-#define MAX_4_BYTE_CHAR 0x1FFFFF
-#define MAX_5_BYTE_CHAR 0x3FFF7F
+enum { MAX_1_BYTE_CHAR = 0x7F };
+enum { MAX_2_BYTE_CHAR = 0x7FF };
+enum { MAX_3_BYTE_CHAR = 0xFFFF };
+enum { MAX_4_BYTE_CHAR = 0x1FFFFF };
+enum { MAX_5_BYTE_CHAR = 0x3FFF7F };
/* Minimum leading code of multibyte characters. */
-#define MIN_MULTIBYTE_LEADING_CODE 0xC0
+enum { MIN_MULTIBYTE_LEADING_CODE = 0xC0 };
/* Maximum leading code of multibyte characters. Note: this must be
updated if we ever increase MAX_CHAR above. */
-#define MAX_MULTIBYTE_LEADING_CODE 0xF8
+enum { MAX_MULTIBYTE_LEADING_CODE = 0xF8 };
/* Unicode character values. */
enum
@@ -81,33 +81,57 @@ enum
};
extern int char_string (unsigned, unsigned char *);
+extern int string_char (const unsigned char *,
+ const unsigned char **, int *);
/* UTF-8 encodings. Use \x escapes, so they are portable to pre-C11
compilers and can be concatenated with ordinary string literals. */
#define uLSQM "\xE2\x80\x98" /* U+2018 LEFT SINGLE QUOTATION MARK */
#define uRSQM "\xE2\x80\x99" /* U+2019 RIGHT SINGLE QUOTATION MARK */
-/* Nonzero iff C is a character that corresponds to a raw 8-bit
+/* True iff C is a character that corresponds to a raw 8-bit
byte. */
-#define CHAR_BYTE8_P(c) ((c) > MAX_5_BYTE_CHAR)
+INLINE bool
+CHAR_BYTE8_P (int c)
+{
+ return MAX_5_BYTE_CHAR < c;
+}
/* Return the character code for raw 8-bit byte BYTE. */
-#define BYTE8_TO_CHAR(byte) ((byte) + 0x3FFF00)
+INLINE int
+BYTE8_TO_CHAR (int byte)
+{
+ return byte + 0x3FFF00;
+}
-#define UNIBYTE_TO_CHAR(byte) \
- (ASCII_CHAR_P (byte) ? (byte) : BYTE8_TO_CHAR (byte))
+INLINE int
+UNIBYTE_TO_CHAR (int byte)
+{
+ return ASCII_CHAR_P (byte) ? byte : BYTE8_TO_CHAR (byte);
+}
/* Return the raw 8-bit byte for character C. */
-#define CHAR_TO_BYTE8(c) (CHAR_BYTE8_P (c) ? (c) - 0x3FFF00 : (c & 0xFF))
+INLINE int
+CHAR_TO_BYTE8 (int c)
+{
+ return CHAR_BYTE8_P (c) ? c - 0x3FFF00 : c & 0xFF;
+}
/* Return the raw 8-bit byte for character C,
or -1 if C doesn't correspond to a byte. */
-#define CHAR_TO_BYTE_SAFE(c) \
- (ASCII_CHAR_P (c) ? c : (CHAR_BYTE8_P (c) ? (c) - 0x3FFF00 : -1))
+INLINE int
+CHAR_TO_BYTE_SAFE (int c)
+{
+ return ASCII_CHAR_P (c) ? c : CHAR_BYTE8_P (c) ? c - 0x3FFF00 : -1;
+}
-/* Nonzero iff BYTE is the 1st byte of a multibyte form of a character
+/* True iff BYTE is the 1st byte of a multibyte form of a character
that corresponds to a raw 8-bit byte. */
-#define CHAR_BYTE8_HEAD_P(byte) ((byte) == 0xC0 || (byte) == 0xC1)
+INLINE bool
+CHAR_BYTE8_HEAD_P (int byte)
+{
+ return byte == 0xC0 || byte == 0xC1;
+}
/* If C is not ASCII, make it unibyte. */
#define MAKE_CHAR_UNIBYTE(c) \
@@ -122,10 +146,7 @@ extern int char_string (unsigned, unsigned char *);
(eassert ((c) >= 0 && (c) < 256), (c) = UNIBYTE_TO_CHAR (c))
/* This is the maximum byte length of multibyte form. */
-#define MAX_MULTIBYTE_LENGTH 5
-
-/* Nonzero iff X is a character. */
-#define CHARACTERP(x) (FIXNATP (x) && XFIXNAT (x) <= MAX_CHAR)
+enum { MAX_MULTIBYTE_LENGTH = 5 };
/* Nonzero iff C is valid as a character code. */
INLINE bool
@@ -134,52 +155,69 @@ CHAR_VALID_P (intmax_t c)
return 0 <= c && c <= MAX_CHAR;
}
+/* Nonzero iff X is a character. */
+INLINE bool
+CHARACTERP (Lisp_Object x)
+{
+ return FIXNUMP (x) && CHAR_VALID_P (XFIXNUM (x));
+}
+
/* Check if Lisp object X is a character or not. */
-#define CHECK_CHARACTER(x) \
- CHECK_TYPE (CHARACTERP (x), Qcharacterp, x)
+INLINE void
+CHECK_CHARACTER (Lisp_Object x)
+{
+ CHECK_TYPE (CHARACTERP (x), Qcharacterp, x);
+}
-#define CHECK_CHARACTER_CAR(x) \
- do { \
- Lisp_Object tmp = XCAR (x); \
- CHECK_CHARACTER (tmp); \
- } while (false)
+INLINE void
+CHECK_CHARACTER_CAR (Lisp_Object x)
+{
+ CHECK_CHARACTER (XCAR (x));
+}
-#define CHECK_CHARACTER_CDR(x) \
- do { \
- Lisp_Object tmp = XCDR (x); \
- CHECK_CHARACTER (tmp); \
- } while (false)
+INLINE void
+CHECK_CHARACTER_CDR (Lisp_Object x)
+{
+ CHECK_CHARACTER (XCDR (x));
+}
-/* Nonzero iff C is a character of code less than 0x100. */
+/* True iff C is a character of code less than 0x100. */
INLINE bool
SINGLE_BYTE_CHAR_P (intmax_t c)
{
return 0 <= c && c < 0x100;
}
-/* Nonzero if character C has a printable glyph. */
-#define CHAR_PRINTABLE_P(c) \
- (((c) >= 32 && (c) < 127) \
- || ! NILP (CHAR_TABLE_REF (Vprintable_chars, (c))))
+/* True if character C has a printable glyph. */
+INLINE bool
+CHAR_PRINTABLE_P (int c)
+{
+ return ((32 <= c && c < 127)
+ || ! NILP (CHAR_TABLE_REF (Vprintable_chars, c)));
+}
/* Return byte length of multibyte form for character C. */
-#define CHAR_BYTES(c) \
- ( (c) <= MAX_1_BYTE_CHAR ? 1 \
- : (c) <= MAX_2_BYTE_CHAR ? 2 \
- : (c) <= MAX_3_BYTE_CHAR ? 3 \
- : (c) <= MAX_4_BYTE_CHAR ? 4 \
- : (c) <= MAX_5_BYTE_CHAR ? 5 \
- : 2)
-
+INLINE int
+CHAR_BYTES (int c)
+{
+ return ((MAX_5_BYTE_CHAR < c ? -2 : 1)
+ + (MAX_1_BYTE_CHAR < c)
+ + (MAX_2_BYTE_CHAR < c)
+ + (MAX_3_BYTE_CHAR < c)
+ + (MAX_4_BYTE_CHAR < c));
+}
/* Return the leading code of multibyte form of C. */
-#define CHAR_LEADING_CODE(c) \
- ((c) <= MAX_1_BYTE_CHAR ? c \
- : (c) <= MAX_2_BYTE_CHAR ? (0xC0 | ((c) >> 6)) \
- : (c) <= MAX_3_BYTE_CHAR ? (0xE0 | ((c) >> 12)) \
- : (c) <= MAX_4_BYTE_CHAR ? (0xF0 | ((c) >> 18)) \
- : (c) <= MAX_5_BYTE_CHAR ? 0xF8 \
- : (0xC0 | (((c) >> 6) & 0x01)))
+INLINE int
+CHAR_LEADING_CODE (int c)
+{
+ return (c <= MAX_1_BYTE_CHAR ? c
+ : c <= MAX_2_BYTE_CHAR ? 0xC0 | (c >> 6)
+ : c <= MAX_3_BYTE_CHAR ? 0xE0 | (c >> 12)
+ : c <= MAX_4_BYTE_CHAR ? 0xF0 | (c >> 18)
+ : c <= MAX_5_BYTE_CHAR ? 0xF8
+ : 0xC0 | ((c >> 6) & 0x01));
+}
/* Store multibyte form of the character C in P. The caller should
@@ -217,10 +255,13 @@ CHAR_STRING (int c, unsigned char *p)
least MAX_MULTIBYTE_LENGTH bytes area at P in advance. Returns the
length of the multibyte form. */
-#define BYTE8_STRING(b, p) \
- ((p)[0] = (0xC0 | (((b) >> 6) & 0x01)), \
- (p)[1] = (0x80 | ((b) & 0x3F)), \
- 2)
+INLINE int
+BYTE8_STRING (int b, unsigned char *p)
+{
+ p[0] = 0xC0 | ((b >> 6) & 0x01);
+ p[1] = 0x80 | (b & 0x3F);
+ return 2;
+}
/* Store multibyte form of the character C in P and advance P to the
@@ -246,28 +287,42 @@ CHAR_STRING (int c, unsigned char *p)
} while (false)
-/* Nonzero iff BYTE starts a non-ASCII character in a multibyte
- form. */
-#define LEADING_CODE_P(byte) (((byte) & 0xC0) == 0xC0)
+/* True iff BYTE starts a non-ASCII character in a multibyte form. */
+INLINE bool
+LEADING_CODE_P (int byte)
+{
+ return (byte & 0xC0) == 0xC0;
+}
-/* Nonzero iff BYTE is a trailing code of a non-ASCII character in a
+/* True iff BYTE is a trailing code of a non-ASCII character in a
multibyte form. */
-#define TRAILING_CODE_P(byte) (((byte) & 0xC0) == 0x80)
+INLINE bool
+TRAILING_CODE_P (int byte)
+{
+ return (byte & 0xC0) == 0x80;
+}
-/* Nonzero iff BYTE starts a character in a multibyte form.
+/* True iff BYTE starts a character in a multibyte form.
This is equivalent to:
(ASCII_CHAR_P (byte) || LEADING_CODE_P (byte)) */
-#define CHAR_HEAD_P(byte) (((byte) & 0xC0) != 0x80)
+INLINE bool
+CHAR_HEAD_P (int byte)
+{
+ return (byte & 0xC0) != 0x80;
+}
/* How many bytes a character that starts with BYTE occupies in a
- multibyte form. Unlike MULTIBYTE_LENGTH below, this macro does not
+ multibyte form. Unlike MULTIBYTE_LENGTH below, this function does not
validate the multibyte form, but looks only at its first byte. */
-#define BYTES_BY_CHAR_HEAD(byte) \
- (!((byte) & 0x80) ? 1 \
- : !((byte) & 0x20) ? 2 \
- : !((byte) & 0x10) ? 3 \
- : !((byte) & 0x08) ? 4 \
- : 5)
+INLINE int
+BYTES_BY_CHAR_HEAD (int byte)
+{
+ return (!(byte & 0x80) ? 1
+ : !(byte & 0x20) ? 2
+ : !(byte & 0x10) ? 3
+ : !(byte & 0x08) ? 4
+ : 5);
+}
/* The byte length of multibyte form at unibyte string P ending at
@@ -275,34 +330,40 @@ CHAR_STRING (int c, unsigned char *p)
return 0. Unlike BYTES_BY_CHAR_HEAD, this macro validates the
multibyte form. */
-#define MULTIBYTE_LENGTH(p, pend) \
- (p >= pend ? 0 \
- : !((p)[0] & 0x80) ? 1 \
- : ((p + 1 >= pend) || (((p)[1] & 0xC0) != 0x80)) ? 0 \
- : ((p)[0] & 0xE0) == 0xC0 ? 2 \
- : ((p + 2 >= pend) || (((p)[2] & 0xC0) != 0x80)) ? 0 \
- : ((p)[0] & 0xF0) == 0xE0 ? 3 \
- : ((p + 3 >= pend) || (((p)[3] & 0xC0) != 0x80)) ? 0 \
- : ((p)[0] & 0xF8) == 0xF0 ? 4 \
- : ((p + 4 >= pend) || (((p)[4] & 0xC0) != 0x80)) ? 0 \
- : (p)[0] == 0xF8 && ((p)[1] & 0xF0) == 0x80 ? 5 \
- : 0)
+INLINE int
+MULTIBYTE_LENGTH (unsigned char const *p, unsigned char const *pend)
+{
+ return (! (p < pend) ? 0
+ : ! (p[0] & 0x80) ? 1
+ : ! (p + 1 < pend && (p[1] & 0xC0) == 0x80) ? 0
+ : (p[0] & 0xE0) == 0xC0 ? 2
+ : ! (p + 2 < pend && (p[2] & 0xC0) == 0x80) ? 0
+ : (p[0] & 0xF0) == 0xE0 ? 3
+ : ! (p + 3 < pend && (p[3] & 0xC0) == 0x80) ? 0
+ : (p[0] & 0xF8) == 0xF0 ? 4
+ : ! (p + 4 < pend && (p[4] & 0xC0) == 0x80) ? 0
+ : p[0] == 0xF8 && (p[1] & 0xF0) == 0x80 ? 5
+ : 0);
+}
/* Like MULTIBYTE_LENGTH, but don't check the ending address. The
multibyte form is still validated, unlike BYTES_BY_CHAR_HEAD. */
-#define MULTIBYTE_LENGTH_NO_CHECK(p) \
- (!((p)[0] & 0x80) ? 1 \
- : ((p)[1] & 0xC0) != 0x80 ? 0 \
- : ((p)[0] & 0xE0) == 0xC0 ? 2 \
- : ((p)[2] & 0xC0) != 0x80 ? 0 \
- : ((p)[0] & 0xF0) == 0xE0 ? 3 \
- : ((p)[3] & 0xC0) != 0x80 ? 0 \
- : ((p)[0] & 0xF8) == 0xF0 ? 4 \
- : ((p)[4] & 0xC0) != 0x80 ? 0 \
- : (p)[0] == 0xF8 && ((p)[1] & 0xF0) == 0x80 ? 5 \
- : 0)
+INLINE int
+MULTIBYTE_LENGTH_NO_CHECK (unsigned char const *p)
+{
+ return (!(p[0] & 0x80) ? 1
+ : (p[1] & 0xC0) != 0x80 ? 0
+ : (p[0] & 0xE0) == 0xC0 ? 2
+ : (p[2] & 0xC0) != 0x80 ? 0
+ : (p[0] & 0xF0) == 0xE0 ? 3
+ : (p[3] & 0xC0) != 0x80 ? 0
+ : (p[0] & 0xF8) == 0xF0 ? 4
+ : (p[4] & 0xC0) != 0x80 ? 0
+ : p[0] == 0xF8 && (p[1] & 0xF0) == 0x80 ? 5
+ : 0);
+}
/* If P is before LIMIT, advance P to the next character boundary.
Assumes that P is already at a character boundary of the same
@@ -333,18 +394,21 @@ CHAR_STRING (int c, unsigned char *p)
/* Return the character code of character whose multibyte form is at P. */
-#define STRING_CHAR(p) \
- (!((p)[0] & 0x80) \
- ? (p)[0] \
- : ! ((p)[0] & 0x20) \
- ? (((((p)[0] & 0x1F) << 6) \
- | ((p)[1] & 0x3F)) \
- + (((unsigned char) (p)[0]) < 0xC2 ? 0x3FFF80 : 0)) \
- : ! ((p)[0] & 0x10) \
- ? ((((p)[0] & 0x0F) << 12) \
- | (((p)[1] & 0x3F) << 6) \
- | ((p)[2] & 0x3F)) \
- : string_char ((p), NULL, NULL))
+INLINE int
+STRING_CHAR (unsigned char const *p)
+{
+ return (!(p[0] & 0x80)
+ ? p[0]
+ : ! (p[0] & 0x20)
+ ? ((((p[0] & 0x1F) << 6)
+ | (p[1] & 0x3F))
+ + (p[0] < 0xC2 ? 0x3FFF80 : 0))
+ : ! (p[0] & 0x10)
+ ? (((p[0] & 0x0F) << 12)
+ | ((p[1] & 0x3F) << 6)
+ | (p[2] & 0x3F))
+ : string_char (p, NULL, NULL));
+}
/* Like STRING_CHAR, but set ACTUAL_LEN to the length of multibyte
@@ -578,58 +642,19 @@ CHAR_STRING (int c, unsigned char *p)
} while (false)
-/* Return a non-outlandish value for the tab width. */
-
-#define SANE_TAB_WIDTH(buf) sanitize_tab_width (BVAR (buf, tab_width))
-
-INLINE int
-sanitize_tab_width (Lisp_Object width)
-{
- return (FIXNUMP (width) && 0 < XFIXNUM (width) && XFIXNUM (width) <= 1000
- ? XFIXNUM (width) : 8);
-}
-
-/* Return the width of ASCII character C. The width is measured by
- how many columns C will occupy on the screen when displayed in the
- current buffer. */
-
-#define ASCII_CHAR_WIDTH(c) \
- (c < 0x20 \
- ? (c == '\t' \
- ? SANE_TAB_WIDTH (current_buffer) \
- : (c == '\n' ? 0 : (NILP (BVAR (current_buffer, ctl_arrow)) ? 4 : 2))) \
- : (c < 0x7f \
- ? 1 \
- : ((NILP (BVAR (current_buffer, ctl_arrow)) ? 4 : 2))))
-
-/* Return a non-outlandish value for a character width. */
+/* If C is a variation selector, return the index of the
+ variation selector (1..256). Otherwise, return 0. */
INLINE int
-sanitize_char_width (EMACS_INT width)
+CHAR_VARIATION_SELECTOR_P (int c)
{
- return 0 <= width && width <= 1000 ? width : 1000;
+ return (c < 0xFE00 ? 0
+ : c <= 0xFE0F ? c - 0xFE00 + 1
+ : c < 0xE0100 ? 0
+ : c <= 0xE01EF ? c - 0xE0100 + 17
+ : 0);
}
-/* Return the width of character C. The width is measured by how many
- columns C will occupy on the screen when displayed in the current
- buffer. The name CHARACTER_WIDTH avoids a collision with <limits.h>
- CHAR_WIDTH when enabled; see ISO/IEC TS 18661-1:2014. */
-
-#define CHARACTER_WIDTH(c) \
- (ASCII_CHAR_P (c) \
- ? ASCII_CHAR_WIDTH (c) \
- : sanitize_char_width (XFIXNUM (CHAR_TABLE_REF (Vchar_width_table, c))))
-
-/* If C is a variation selector, return the index of the
- variation selector (1..256). Otherwise, return 0. */
-
-#define CHAR_VARIATION_SELECTOR_P(c) \
- ((c) < 0xFE00 ? 0 \
- : (c) <= 0xFE0F ? (c) - 0xFE00 + 1 \
- : (c) < 0xE0100 ? 0 \
- : (c) <= 0xE01EF ? (c) - 0xE0100 + 17 \
- : 0)
-
/* Return true if C is a surrogate. */
INLINE bool
@@ -679,8 +704,6 @@ typedef enum {
} unicode_category_t;
extern EMACS_INT char_resolve_modifier_mask (EMACS_INT) ATTRIBUTE_CONST;
-extern int string_char (const unsigned char *,
- const unsigned char **, int *);
extern int translate_char (Lisp_Object, int c);
extern ptrdiff_t count_size_as_multibyte (const unsigned char *, ptrdiff_t);
diff --git a/src/conf_post.h b/src/conf_post.h
index 79fb4cfe8a7..8a6b32998d8 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -290,6 +290,7 @@ extern int emacs_setenv_TZ (char const *);
#define ARG_NONNULL _GL_ARG_NONNULL
#define ATTRIBUTE_CONST _GL_ATTRIBUTE_CONST
+#define ATTRIBUTE_PURE _GL_ATTRIBUTE_PURE
#define ATTRIBUTE_UNUSED _GL_UNUSED
#if GNUC_PREREQ (3, 3, 0) && !defined __ICC
diff --git a/src/fns.c b/src/fns.c
index 138082e07c8..e22fbaaedb9 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -3700,7 +3700,7 @@ base64_decode_1 (const char *from, char *to, ptrdiff_t length,
c = value >> 16 & 0xff;
if (c & multibyte_bit)
- e += BYTE8_STRING (c, e);
+ e += BYTE8_STRING (c, (unsigned char *) e);
else
*e++ = c;
nchars++;
@@ -3742,7 +3742,7 @@ base64_decode_1 (const char *from, char *to, ptrdiff_t length,
c = value >> 8 & 0xff;
if (c & multibyte_bit)
- e += BYTE8_STRING (c, e);
+ e += BYTE8_STRING (c, (unsigned char *) e);
else
*e++ = c;
nchars++;
@@ -3772,7 +3772,7 @@ base64_decode_1 (const char *from, char *to, ptrdiff_t length,
c = value & 0xff;
if (c & multibyte_bit)
- e += BYTE8_STRING (c, e);
+ e += BYTE8_STRING (c, (unsigned char *) e);
else
*e++ = c;
nchars++;
diff --git a/src/lisp.h b/src/lisp.h
index 706ca6b9a82..b4ac017dcf5 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -597,7 +597,7 @@ extern Lisp_Object make_biguint (uintmax_t);
extern uintmax_t check_uinteger_max (Lisp_Object, uintmax_t);
/* Defined in chartab.c. */
-extern Lisp_Object char_table_ref (Lisp_Object, int);
+extern Lisp_Object char_table_ref (Lisp_Object, int) ATTRIBUTE_PURE;
extern void char_table_set (Lisp_Object, int, Lisp_Object);
/* Defined in data.c. */