]> git.eshelyaron.com Git - emacs.git/commitdiff
Use C99-style flexible array members if available.
authorPaul Eggert <eggert@cs.ucla.edu>
Fri, 21 Jun 2013 20:11:44 +0000 (13:11 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Fri, 21 Jun 2013 20:11:44 +0000 (13:11 -0700)
This avoids some subtle aliasing issues, which typically
aren't a problem with GCC but may be a problem elsewhere.
* lib-src/ebrowse.c (struct member, struct alias, struct sym):
Use FLEXIBLE_ARRAY_MEMBER.
(add_sym, add_member, make_namespace, register_namespace_alias):
Use offsetof (struct, flex_array_member), not sizeof (struct), as
that ports better to pre-C99 non-GCC.
* src/alloc.c (sdata): New typedef, replacing the old struct sdata.
It is a struct if GC_CHECK_STRING_BYTES, a union otherwise.
In either case, it uses a flexible array member rather than
the old struct hack.  All uses changed.
(SDATA_NBYTES, sweep_strings) [!GC_CHECK_STRING_BYTES]:
Adjust to sdata reorganization.
* src/alloc.c (VBLOCK_BYTES_MIN, allocate_vectorlike, Fgarbage_collect):
Use offsetof (struct, flex_array_member), not sizeof (struct), as
that ports better to pre-C99 non-GCC.
* src/chartab.c (Fmake_char_table, make_sub_char_table, copy_char_table):
Use CHAR_TABLE_STANDARD_SLOTS rather than its definition,
as the latter has changed.
* src/conf_post.h (FLEXIBLE_ARRAY_MEMBER): Move here from w32.c,
and port better to pre-C99 GCC.
* src/image.c (struct xpm_cached_color):
* src/lisp.h (struct Lisp_Vector, struct Lisp_Bool_Vector)
(struct Lisp_Char_Table, struct Lisp_Sub_Char_Table):
Use FLEXIBLE_ARRAY_MEMBER.
* src/lisp.h (string_bytes) [GC_CHECK_STRING_BYTES]:
Move decl to top level so it gets checked against implementation.
(CHAR_TABLE_STANDARD_SLOTS): Adjust to struct Lisp_Char_Table change.
* src/w32.c (FLEXIBLE_ARRAY_MEMBER): Move to conf_post.h.

lib-src/ChangeLog
lib-src/ebrowse.c
src/ChangeLog
src/alloc.c
src/chartab.c
src/conf_post.h
src/image.c
src/lisp.h
src/w32.c

index 0e4cf0b283353715301c9ddb7503b0727179fdfd..62ee45aac51567c61c6b35a140ad78392a609caa 100644 (file)
@@ -1,3 +1,12 @@
+2013-06-21  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Use C99-style flexible array members if available.
+       * ebrowse.c (struct member, struct alias, struct sym):
+       Use FLEXIBLE_ARRAY_MEMBER.
+       (add_sym, add_member, make_namespace, register_namespace_alias):
+       Use offsetof (struct, flex_array_member), not sizeof (struct), as
+       that ports better to pre-C99 non-GCC.
+
 2013-05-29  Eli Zaretskii  <eliz@gnu.org>
 
        * Makefile.in (mostlyclean): Remove *.res files.
index 3a237daf5f8a6c96c50085180ec7e91ce7619553..81d0cf0a19e3c8eedf25fac6fe761255531dcecc 100644 (file)
@@ -237,7 +237,7 @@ struct member
   char *def_regexp;            /* Regular expression matching definition.  */
   const char *def_filename;    /* File name of definition.  */
   int def_pos;                 /* Buffer position of definition.  */
-  char name[1];                        /* Member name.  */
+  char name[FLEXIBLE_ARRAY_MEMBER]; /* Member name.  */
 };
 
 /* Structures of this type are used to connect class structures with
@@ -256,7 +256,7 @@ struct alias
   struct alias *next;          /* Next in list.  */
   struct sym *namesp;          /* Namespace in which defined.  */
   struct link *aliasee;                /* List of aliased namespaces (A::B::C...).  */
-  char name[1];                        /* Alias name.  */
+  char name[FLEXIBLE_ARRAY_MEMBER]; /* Alias name.  */
 };
 
 /* The structure used to describe a class in the symbol table,
@@ -280,7 +280,7 @@ struct sym
   const char *filename;                /* File in which it can be found.  */
   const char *sfilename;       /* File in which members can be found.  */
   struct sym *namesp;          /* Namespace in which defined. .  */
-  char name[1];                 /* Name of the class.  */
+  char name[FLEXIBLE_ARRAY_MEMBER]; /* Name of the class.  */
 };
 
 /* Experimental: Print info for `--position-info'.  We print
@@ -567,8 +567,8 @@ add_sym (const char *name, struct sym *nested_in_class)
          puts (name);
        }
 
-      sym = (struct sym *) xmalloc (sizeof *sym + strlen (name));
-      memset (sym, 0, sizeof *sym);
+      sym = xmalloc (offsetof (struct sym, name) + strlen (name) + 1);
+      memset (sym, 0, offsetof (struct sym, name));
       strcpy (sym->name, name);
       sym->namesp = scope;
       sym->next = class_table[h];
@@ -852,7 +852,8 @@ add_global_decl (char *name, char *regexp, int pos, unsigned int hash, int var,
 static struct member *
 add_member (struct sym *cls, char *name, int var, int sc, unsigned int hash)
 {
-  struct member *m = (struct member *) xmalloc (sizeof *m + strlen (name));
+  struct member *m = xmalloc (offsetof (struct member, name)
+                             + strlen (name) + 1);
   struct member **list;
   struct member *p;
   struct member *prev;
@@ -962,8 +963,8 @@ mark_inherited_virtual (void)
 static struct sym *
 make_namespace (char *name, struct sym *context)
 {
-  struct sym *s = (struct sym *) xmalloc (sizeof *s + strlen (name));
-  memset (s, 0, sizeof *s);
+  struct sym *s = xmalloc (offsetof (struct sym, name) + strlen (name) + 1);
+  memset (s, 0, offsetof (struct sym, name));
   strcpy (s->name, name);
   s->next = all_namespaces;
   s->namesp = context;
@@ -1046,7 +1047,7 @@ register_namespace_alias (char *new_name, struct link *old_name)
     if (streq (new_name, al->name) && (al->namesp == current_namespace))
       return;
 
-  al = (struct alias *) xmalloc (sizeof *al + strlen (new_name));
+  al = xmalloc (offsetof (struct alias, name) + strlen (new_name) + 1);
   strcpy (al->name, new_name);
   al->next = namespace_alias_table[h];
   al->namesp = current_namespace;
index 4e52f5b28187bbe01fa9de10f0f3e8ed3d0209af..4821f5fb7ebdd509134a56ec0a4938c73d9af931 100644 (file)
@@ -1,3 +1,31 @@
+2013-06-21  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Use C99-style flexible array members if available.
+       This avoids some subtle aliasing issues, which typically
+       aren't a problem with GCC but may be a problem elsewhere.
+       * alloc.c (sdata): New typedef, replacing the old struct sdata.
+       It is a struct if GC_CHECK_STRING_BYTES, a union otherwise.
+       In either case, it uses a flexible array member rather than
+       the old struct hack.  All uses changed.
+       (SDATA_NBYTES, sweep_strings) [!GC_CHECK_STRING_BYTES]:
+       Adjust to sdata reorganization.
+       * alloc.c (VBLOCK_BYTES_MIN, allocate_vectorlike, Fgarbage_collect):
+       Use offsetof (struct, flex_array_member), not sizeof (struct), as
+       that ports better to pre-C99 non-GCC.
+       * chartab.c (Fmake_char_table, make_sub_char_table, copy_char_table):
+       Use CHAR_TABLE_STANDARD_SLOTS rather than its definition,
+       as the latter has changed.
+       * conf_post.h (FLEXIBLE_ARRAY_MEMBER): Move here from w32.c,
+       and port better to pre-C99 GCC.
+       * image.c (struct xpm_cached_color):
+       * lisp.h (struct Lisp_Vector, struct Lisp_Bool_Vector)
+       (struct Lisp_Char_Table, struct Lisp_Sub_Char_Table):
+       Use FLEXIBLE_ARRAY_MEMBER.
+       * lisp.h (string_bytes) [GC_CHECK_STRING_BYTES]:
+       Move decl to top level so it gets checked against implementation.
+       (CHAR_TABLE_STANDARD_SLOTS): Adjust to struct Lisp_Char_Table change.
+       * w32.c (FLEXIBLE_ARRAY_MEMBER): Move to conf_post.h.
+
 2013-06-20  Paul Eggert  <eggert@cs.ucla.edu>
 
        * syntax.c: Integer cleanups.
index d277dd2419be164f22a6fde7d40dbdfc59f8f036..eaef0d4b79747f31ca9ce7b696448d107cd4b5dd 100644 (file)
@@ -1260,7 +1260,7 @@ mark_interval (register INTERVAL i, Lisp_Object dummy)
    When a Lisp_String is freed during GC, it is put back on
    string_free_list, and its `data' member and its sdata's `string'
    pointer is set to null.  The size of the string is recorded in the
-   `u.nbytes' member of the sdata.  So, sdata structures that are no
+   `n.nbytes' member of the sdata.  So, sdata structures that are no
    longer used, can be easily recognized, and it's easy to compact the
    sblocks of small strings which we do in compact_small_strings.  */
 
@@ -1274,10 +1274,12 @@ mark_interval (register INTERVAL i, Lisp_Object dummy)
 
 #define LARGE_STRING_BYTES 1024
 
-/* Structure describing string memory sub-allocated from an sblock.
+/* Struct or union describing string memory sub-allocated from an sblock.
    This is where the contents of Lisp strings are stored.  */
 
-struct sdata
+#ifdef GC_CHECK_STRING_BYTES
+
+typedef struct
 {
   /* Back-pointer to the string this sdata belongs to.  If null, this
      structure is free, and the NBYTES member of the union below
@@ -1287,34 +1289,42 @@ struct sdata
      contents.  */
   struct Lisp_String *string;
 
-#ifdef GC_CHECK_STRING_BYTES
-
   ptrdiff_t nbytes;
-  unsigned char data[1];
+  unsigned char data[FLEXIBLE_ARRAY_MEMBER];
+} sdata;
 
 #define SDATA_NBYTES(S)        (S)->nbytes
 #define SDATA_DATA(S)  (S)->data
 #define SDATA_SELECTOR(member) member
 
-#else /* not GC_CHECK_STRING_BYTES */
+#else
 
-  union
+typedef union
+{
+  struct Lisp_String *string;
+
+  /* When STRING is non-null.  */
+  struct
   {
-    /* When STRING is non-null.  */
-    unsigned char data[1];
+    struct Lisp_String *string;
+    unsigned char data[FLEXIBLE_ARRAY_MEMBER];
+  } u;
 
-    /* When STRING is null.  */
+  /* When STRING is null.  */
+  struct
+  {
+    struct Lisp_String *string;
     ptrdiff_t nbytes;
-  } u;
+  } n;
+} sdata;
 
-#define SDATA_NBYTES(S)        (S)->u.nbytes
+#define SDATA_NBYTES(S)        (S)->n.nbytes
 #define SDATA_DATA(S)  (S)->u.data
 #define SDATA_SELECTOR(member) u.member
 
 #endif /* not GC_CHECK_STRING_BYTES */
 
-#define SDATA_DATA_OFFSET offsetof (struct sdata, SDATA_SELECTOR (data))
-};
+#define SDATA_DATA_OFFSET offsetof (sdata, SDATA_SELECTOR (data))
 
 
 /* Structure describing a block of memory which is sub-allocated to
@@ -1329,10 +1339,10 @@ struct sblock
 
   /* Pointer to the next free sdata block.  This points past the end
      of the sblock if there isn't any space left in this block.  */
-  struct sdata *next_free;
+  sdata *next_free;
 
   /* Start of data.  */
-  struct sdata first_data;
+  sdata first_data;
 };
 
 /* Number of Lisp strings in a string_block structure.  The 1020 is
@@ -1388,7 +1398,7 @@ static EMACS_INT total_string_bytes;
    a pointer to the `u.data' member of its sdata structure; the
    structure starts at a constant offset in front of that.  */
 
-#define SDATA_OF_STRING(S) ((struct sdata *) ((S)->data - SDATA_DATA_OFFSET))
+#define SDATA_OF_STRING(S) ((sdata *) ((S)->data - SDATA_DATA_OFFSET))
 
 
 #ifdef GC_CHECK_STRING_OVERRUN
@@ -1487,7 +1497,7 @@ string_bytes (struct Lisp_String *s)
 static void
 check_sblock (struct sblock *b)
 {
-  struct sdata *from, *end, *from_end;
+  sdata *from, *end, *from_end;
 
   end = b->next_free;
 
@@ -1501,7 +1511,7 @@ check_sblock (struct sblock *b)
         same as the one recorded in the sdata structure.  */
       nbytes = SDATA_SIZE (from->string ? string_bytes (from->string)
                           : SDATA_NBYTES (from));
-      from_end = (struct sdata *) ((char *) from + nbytes + GC_STRING_EXTRA);
+      from_end = (sdata *) ((char *) from + nbytes + GC_STRING_EXTRA);
     }
 }
 
@@ -1631,7 +1641,7 @@ void
 allocate_string_data (struct Lisp_String *s,
                      EMACS_INT nchars, EMACS_INT nbytes)
 {
-  struct sdata *data, *old_data;
+  sdata *data, *old_data;
   struct sblock *b;
   ptrdiff_t needed, old_nbytes;
 
@@ -1701,7 +1711,7 @@ allocate_string_data (struct Lisp_String *s,
     b = current_sblock;
 
   data = b->next_free;
-  b->next_free = (struct sdata *) ((char *) data + needed + GC_STRING_EXTRA);
+  b->next_free = (sdata *) ((char *) data + needed + GC_STRING_EXTRA);
 
   MALLOC_UNBLOCK_INPUT;
 
@@ -1772,7 +1782,7 @@ sweep_strings (void)
              else
                {
                  /* String is dead.  Put it on the free-list.  */
-                 struct sdata *data = SDATA_OF_STRING (s);
+                 sdata *data = SDATA_OF_STRING (s);
 
                  /* Save the size of S in its sdata so that we know
                     how large that is.  Reset the sdata's string
@@ -1781,7 +1791,7 @@ sweep_strings (void)
                  if (string_bytes (s) != SDATA_NBYTES (data))
                    emacs_abort ();
 #else
-                 data->u.nbytes = STRING_BYTES (s);
+                 data->n.nbytes = STRING_BYTES (s);
 #endif
                  data->string = NULL;
 
@@ -1862,13 +1872,13 @@ static void
 compact_small_strings (void)
 {
   struct sblock *b, *tb, *next;
-  struct sdata *from, *to, *end, *tb_end;
-  struct sdata *to_end, *from_end;
+  sdata *from, *to, *end, *tb_end;
+  sdata *to_end, *from_end;
 
   /* TB is the sblock we copy to, TO is the sdata within TB we copy
      to, and TB_END is the end of TB.  */
   tb = oldest_sblock;
-  tb_end = (struct sdata *) ((char *) tb + SBLOCK_SIZE);
+  tb_end = (sdata *) ((char *) tb + SBLOCK_SIZE);
   to = &tb->first_data;
 
   /* Step through the blocks from the oldest to the youngest.  We
@@ -1897,7 +1907,7 @@ compact_small_strings (void)
          eassert (nbytes <= LARGE_STRING_BYTES);
 
          nbytes = SDATA_SIZE (nbytes);
-         from_end = (struct sdata *) ((char *) from + nbytes + GC_STRING_EXTRA);
+         from_end = (sdata *) ((char *) from + nbytes + GC_STRING_EXTRA);
 
 #ifdef GC_CHECK_STRING_OVERRUN
          if (memcmp (string_overrun_cookie,
@@ -1910,14 +1920,14 @@ compact_small_strings (void)
          if (s)
            {
              /* If TB is full, proceed with the next sblock.  */
-             to_end = (struct sdata *) ((char *) to + nbytes + GC_STRING_EXTRA);
+             to_end = (sdata *) ((char *) to + nbytes + GC_STRING_EXTRA);
              if (to_end > tb_end)
                {
                  tb->next_free = to;
                  tb = tb->next;
-                 tb_end = (struct sdata *) ((char *) tb + SBLOCK_SIZE);
+                 tb_end = (sdata *) ((char *) tb + SBLOCK_SIZE);
                  to = &tb->first_data;
-                 to_end = (struct sdata *) ((char *) to + nbytes + GC_STRING_EXTRA);
+                 to_end = (sdata *) ((char *) to + nbytes + GC_STRING_EXTRA);
                }
 
              /* Copy, and update the string's `data' pointer.  */
@@ -2581,7 +2591,7 @@ verify (VECTOR_BLOCK_SIZE <= (1 << PSEUDOVECTOR_SIZE_BITS));
 
 /* Size of the minimal vector allocated from block.  */
 
-#define VBLOCK_BYTES_MIN vroundup (sizeof (struct Lisp_Vector))
+#define VBLOCK_BYTES_MIN vroundup (header_size + sizeof (Lisp_Object))
 
 /* Size of the largest vector allocated from block.  */
 
@@ -2938,7 +2948,8 @@ allocate_vectorlike (ptrdiff_t len)
       else
        {
          struct large_vector *lv
-           = lisp_malloc (sizeof (*lv) + (len - 1) * word_size,
+           = lisp_malloc ((offsetof (struct large_vector, v.contents)
+                           + len * word_size),
                           MEM_TYPE_VECTORLIKE);
          lv->next.vector = large_vectors;
          large_vectors = lv;
@@ -5416,7 +5427,8 @@ See Info node `(elisp)Garbage Collection'.  */)
     total[4] = list3 (Qstring_bytes, make_number (1),
                      bounded_number (total_string_bytes));
 
-    total[5] = list3 (Qvectors, make_number (sizeof (struct Lisp_Vector)),
+    total[5] = list3 (Qvectors,
+                     make_number (header_size + sizeof (Lisp_Object)),
                      bounded_number (total_vectors));
 
     total[6] = list4 (Qvector_slots, make_number (word_size),
index 1c76e5a21e91a02f3e17538e08dbc0a9d58ff9d1..b7b9590a5382f34bba86b1e3f8b503f3a1dce292 100644 (file)
@@ -128,7 +128,7 @@ the char-table has no extra slot.  */)
       n_extras = XINT (n);
     }
 
-  size = VECSIZE (struct Lisp_Char_Table) - 1 + n_extras;
+  size = CHAR_TABLE_STANDARD_SLOTS + n_extras;
   vector = Fmake_vector (make_number (size), init);
   XSETPVECTYPE (XVECTOR (vector), PVEC_CHAR_TABLE);
   set_char_table_parent (vector, Qnil);
@@ -141,7 +141,7 @@ static Lisp_Object
 make_sub_char_table (int depth, int min_char, Lisp_Object defalt)
 {
   Lisp_Object table;
-  int size = VECSIZE (struct Lisp_Sub_Char_Table) - 1 + chartab_size[depth];
+  int size = CHAR_TABLE_STANDARD_SLOTS + chartab_size[depth];
 
   table = Fmake_vector (make_number (size), defalt);
   XSETPVECTYPE (XVECTOR (table), PVEC_SUB_CHAR_TABLE);
@@ -207,7 +207,7 @@ copy_char_table (Lisp_Object table)
        ? copy_sub_char_table (XCHAR_TABLE (table)->contents[i])
        : XCHAR_TABLE (table)->contents[i]));
   set_char_table_ascii (copy, char_table_ascii (copy));
-  size -= VECSIZE (struct Lisp_Char_Table) - 1;
+  size -= CHAR_TABLE_STANDARD_SLOTS;
   for (i = 0; i < size; i++)
     set_char_table_extras (copy, i, XCHAR_TABLE (table)->extras[i]);
 
index 46aea32ef30baf28c494474d9d02a9aee1fa6159..32c4341b7a30527c0928e884391cd3b1eeb0be43 100644 (file)
@@ -243,6 +243,17 @@ extern void _DebPrint (const char *fmt, ...);
 #define INLINE_HEADER_BEGIN _GL_INLINE_HEADER_BEGIN
 #define INLINE_HEADER_END _GL_INLINE_HEADER_END
 
+/* To use the struct hack with N elements, declare the struct like this:
+     struct s { ...; t name[FLEXIBLE_ARRAY_MEMBER]; };
+   and allocate (offsetof (struct s, name) + N * sizeof (t)) bytes.  */
+#if 199901 <= __STDC_VERSION__
+# define FLEXIBLE_ARRAY_MEMBER
+#elif __GNUC__ && !defined __STRICT_ANSI__
+# define FLEXIBLE_ARRAY_MEMBER 0
+#else
+# define FLEXIBLE_ARRAY_MEMBER 1
+#endif
+
 /* Use this to suppress gcc's `...may be used before initialized' warnings. */
 #ifdef lint
 /* Use CODE only if lint checking is in effect.  */
index f9f6ce7004024ee54a700092ed8282ac72ad8056..ffb3cd15e937a2c166eb00c00b9e6d19d84fff2e 100644 (file)
@@ -3057,7 +3057,7 @@ struct xpm_cached_color
   XColor color;
 
   /* Color name.  */
-  char name[1];
+  char name[FLEXIBLE_ARRAY_MEMBER];
 };
 
 /* The hash table used for the color cache, and its bucket vector
index e2d091e98f160b7cd3ec461ba257412b72ead1ee..f4356cd140d09b483fc904c20c2234efeab832a0 100644 (file)
@@ -1073,16 +1073,20 @@ SCHARS (Lisp_Object string)
 {
   return XSTRING (string)->size;
 }
+
+#ifdef GC_CHECK_STRING_BYTES
+extern ptrdiff_t string_bytes (struct Lisp_String *);
+#endif
 LISP_INLINE ptrdiff_t
 STRING_BYTES (struct Lisp_String *s)
 {
 #ifdef GC_CHECK_STRING_BYTES
-  extern ptrdiff_t string_bytes (struct Lisp_String *);
   return string_bytes (s);
 #else
   return s->size_byte < 0 ? s->size : s->size_byte;
 #endif
 }
+
 LISP_INLINE ptrdiff_t
 SBYTES (Lisp_Object string)
 {
@@ -1136,7 +1140,7 @@ struct vectorlike_header
 struct Lisp_Vector
   {
     struct vectorlike_header header;
-    Lisp_Object contents[1];
+    Lisp_Object contents[FLEXIBLE_ARRAY_MEMBER];
   };
 
 /* A boolvector is a kind of vectorlike, with contents are like a string.  */
@@ -1149,7 +1153,7 @@ struct Lisp_Bool_Vector
     /* This is the size in bits.  */
     EMACS_INT size;
     /* This contains the actual bits, packed into bytes.  */
-    unsigned char data[1];
+    unsigned char data[FLEXIBLE_ARRAY_MEMBER];
   };
 
 /* Some handy constants for calculating sizes
@@ -1272,7 +1276,7 @@ struct Lisp_Char_Table
     Lisp_Object contents[(1 << CHARTAB_SIZE_BITS_0)];
 
     /* These hold additional data.  It is a vector.  */
-    Lisp_Object extras[1];
+    Lisp_Object extras[FLEXIBLE_ARRAY_MEMBER];
   };
 
 struct Lisp_Sub_Char_Table
@@ -1293,7 +1297,7 @@ struct Lisp_Sub_Char_Table
     Lisp_Object min_char;
 
     /* Use set_sub_char_table_contents to set this.  */
-    Lisp_Object contents[1];
+    Lisp_Object contents[FLEXIBLE_ARRAY_MEMBER];
   };
 
 LISP_INLINE Lisp_Object
@@ -1366,7 +1370,7 @@ struct Lisp_Subr
    slots.  */
 enum CHAR_TABLE_STANDARD_SLOTS
   {
-    CHAR_TABLE_STANDARD_SLOTS = VECSIZE (struct Lisp_Char_Table) - 1
+    CHAR_TABLE_STANDARD_SLOTS = PSEUDOVECSIZE (struct Lisp_Char_Table, extras)
   };
 
 /* Return the number of "extra" slots in the char table CT.  */
index 7a39a617ee3ad123270673743304290c5b2863d2..230479cd61a2c089471e6143fbae06425f6396f6 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -3785,12 +3785,6 @@ get_rid (PSID sid)
 
 /* Caching SID and account values for faster lokup.  */
 
-#ifdef __GNUC__
-# define FLEXIBLE_ARRAY_MEMBER
-#else
-# define FLEXIBLE_ARRAY_MEMBER 1
-#endif
-
 struct w32_id {
   unsigned rid;
   struct w32_id *next;