xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/objc/objc-encoding.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
136ac495dSmrg /* Routines dealing with ObjC encoding of types
2*8feb0f0bSmrg    Copyright (C) 1992-2020 Free Software Foundation, Inc.
336ac495dSmrg 
436ac495dSmrg This file is part of GCC.
536ac495dSmrg 
636ac495dSmrg GCC is free software; you can redistribute it and/or modify
736ac495dSmrg it under the terms of the GNU General Public License as published by
836ac495dSmrg the Free Software Foundation; either version 3, or (at your option)
936ac495dSmrg any later version.
1036ac495dSmrg 
1136ac495dSmrg GCC is distributed in the hope that it will be useful,
1236ac495dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
1336ac495dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1436ac495dSmrg GNU General Public License for more details.
1536ac495dSmrg 
1636ac495dSmrg You should have received a copy of the GNU General Public License
1736ac495dSmrg along with GCC; see the file COPYING3.  If not see
1836ac495dSmrg <http://www.gnu.org/licenses/>.  */
1936ac495dSmrg 
2036ac495dSmrg #include "config.h"
2136ac495dSmrg #include "system.h"
2236ac495dSmrg #include "coretypes.h"
2336ac495dSmrg #include "tree.h"
2436ac495dSmrg #include "options.h"
2536ac495dSmrg #include "stringpool.h"
2636ac495dSmrg #include "stor-layout.h"
2736ac495dSmrg 
2836ac495dSmrg #ifdef OBJCPLUS
2936ac495dSmrg #include "cp/cp-tree.h"
3036ac495dSmrg #else
3136ac495dSmrg #include "c/c-tree.h"
3236ac495dSmrg #include "c/c-lang.h"
3336ac495dSmrg #endif
3436ac495dSmrg 
3536ac495dSmrg #include "c-family/c-objc.h"
3636ac495dSmrg 
3736ac495dSmrg #include "objc-encoding.h"
3836ac495dSmrg #include "objc-act.h"
3936ac495dSmrg 
4036ac495dSmrg /* For my_build_string().  */
4136ac495dSmrg #include "objc-runtime-shared-support.h"
4236ac495dSmrg 
4336ac495dSmrg /* For BITS_PER_UNIT.  */
4436ac495dSmrg 
4536ac495dSmrg /* When building Objective-C++, we are not linking against the C front-end
4636ac495dSmrg    and so need to replicate the C tree-construction functions in some way.  */
4736ac495dSmrg #ifdef OBJCPLUS
4836ac495dSmrg #define OBJCP_REMAP_FUNCTIONS
4936ac495dSmrg #include "objcp-decl.h"
5036ac495dSmrg #endif  /* OBJCPLUS */
5136ac495dSmrg 
5236ac495dSmrg /* Set up for use of obstacks.  */
5336ac495dSmrg 
5436ac495dSmrg /* This obstack is used to accumulate the encoding of a data type.  */
5536ac495dSmrg static struct obstack util_obstack;
5636ac495dSmrg 
5736ac495dSmrg /* This points to the beginning of obstack contents, so we can free
5836ac495dSmrg    the whole contents.  */
5936ac495dSmrg static char *util_firstobj;
6036ac495dSmrg 
objc_encoding_init(void)6136ac495dSmrg void objc_encoding_init (void)
6236ac495dSmrg {
6336ac495dSmrg   gcc_obstack_init (&util_obstack);
6436ac495dSmrg   util_firstobj = (char *) obstack_finish (&util_obstack);
6536ac495dSmrg }
6636ac495dSmrg 
6736ac495dSmrg int generating_instance_variables = 0;
6836ac495dSmrg 
6936ac495dSmrg static void encode_type_qualifiers (tree);
7036ac495dSmrg static void encode_type (tree, int, int);
7136ac495dSmrg static void encode_field (tree field_decl, int curtype, int format);
7236ac495dSmrg 
7336ac495dSmrg static tree
objc_method_parm_type(tree type)7436ac495dSmrg objc_method_parm_type (tree type)
7536ac495dSmrg {
7636ac495dSmrg   type = TREE_VALUE (TREE_TYPE (type));
7736ac495dSmrg   if (TREE_CODE (type) == TYPE_DECL)
7836ac495dSmrg     type = TREE_TYPE (type);
7936ac495dSmrg   return type;
8036ac495dSmrg }
8136ac495dSmrg 
8236ac495dSmrg static int
objc_encoded_type_size(tree type)8336ac495dSmrg objc_encoded_type_size (tree type)
8436ac495dSmrg {
8536ac495dSmrg   int sz = int_size_in_bytes (type);
8636ac495dSmrg 
8736ac495dSmrg   /* Make all integer and enum types at least as large
8836ac495dSmrg      as an int.  */
8936ac495dSmrg   if (sz > 0 && INTEGRAL_TYPE_P (type))
9036ac495dSmrg     sz = MAX (sz, int_size_in_bytes (integer_type_node));
9136ac495dSmrg   /* Treat arrays as pointers, since that's how they're
9236ac495dSmrg      passed in.  */
9336ac495dSmrg   else if (TREE_CODE (type) == ARRAY_TYPE)
9436ac495dSmrg     sz = int_size_in_bytes (ptr_type_node);
9536ac495dSmrg   return sz;
9636ac495dSmrg }
9736ac495dSmrg 
9836ac495dSmrg /* Encode a method prototype.  */
9936ac495dSmrg tree
encode_method_prototype(tree method_decl)10036ac495dSmrg encode_method_prototype (tree method_decl)
10136ac495dSmrg {
10236ac495dSmrg   tree parms;
10336ac495dSmrg   int parm_offset, i;
10436ac495dSmrg   char buf[40];
10536ac495dSmrg   tree result;
10636ac495dSmrg 
10736ac495dSmrg   /* ONEWAY and BYCOPY, for remote object are the only method qualifiers.  */
10836ac495dSmrg   encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (method_decl)));
10936ac495dSmrg 
11036ac495dSmrg   /* Encode return type.  */
11136ac495dSmrg   encode_type (objc_method_parm_type (method_decl),
11236ac495dSmrg 	       obstack_object_size (&util_obstack),
11336ac495dSmrg 	       OBJC_ENCODE_INLINE_DEFS);
11436ac495dSmrg 
11536ac495dSmrg   /* Stack size.  */
11636ac495dSmrg   /* The first two arguments (self and _cmd) are pointers; account for
11736ac495dSmrg      their size.  */
11836ac495dSmrg   i = int_size_in_bytes (ptr_type_node);
11936ac495dSmrg   parm_offset = 2 * i;
12036ac495dSmrg   for (parms = METHOD_SEL_ARGS (method_decl); parms;
12136ac495dSmrg        parms = DECL_CHAIN (parms))
12236ac495dSmrg     {
12336ac495dSmrg       tree type = objc_method_parm_type (parms);
12436ac495dSmrg       int sz = objc_encoded_type_size (type);
12536ac495dSmrg 
12636ac495dSmrg       /* If a type size is not known, bail out.  */
12736ac495dSmrg       if (sz < 0)
12836ac495dSmrg 	{
12936ac495dSmrg 	  error_at (DECL_SOURCE_LOCATION (method_decl),
13036ac495dSmrg 		    "type %qT does not have a known size",
13136ac495dSmrg 		    type);
13236ac495dSmrg 	  /* Pretend that the encoding succeeded; the compilation will
13336ac495dSmrg 	     fail nevertheless.  */
13436ac495dSmrg 	  goto finish_encoding;
13536ac495dSmrg 	}
13636ac495dSmrg       parm_offset += sz;
13736ac495dSmrg     }
13836ac495dSmrg 
13936ac495dSmrg   sprintf (buf, "%d@0:%d", parm_offset, i);
14036ac495dSmrg   obstack_grow (&util_obstack, buf, strlen (buf));
14136ac495dSmrg 
14236ac495dSmrg   /* Argument types.  */
14336ac495dSmrg   parm_offset = 2 * i;
14436ac495dSmrg   for (parms = METHOD_SEL_ARGS (method_decl); parms;
14536ac495dSmrg        parms = DECL_CHAIN (parms))
14636ac495dSmrg     {
14736ac495dSmrg       tree type = objc_method_parm_type (parms);
14836ac495dSmrg 
14936ac495dSmrg       /* Process argument qualifiers for user supplied arguments.  */
15036ac495dSmrg       encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (parms)));
15136ac495dSmrg 
15236ac495dSmrg       /* Type.  */
15336ac495dSmrg       encode_type (type, obstack_object_size (&util_obstack),
15436ac495dSmrg 		   OBJC_ENCODE_INLINE_DEFS);
15536ac495dSmrg 
15636ac495dSmrg       /* Compute offset.  */
15736ac495dSmrg       sprintf (buf, "%d", parm_offset);
15836ac495dSmrg       parm_offset += objc_encoded_type_size (type);
15936ac495dSmrg 
16036ac495dSmrg       obstack_grow (&util_obstack, buf, strlen (buf));
16136ac495dSmrg     }
16236ac495dSmrg 
16336ac495dSmrg   finish_encoding:
16436ac495dSmrg   obstack_1grow (&util_obstack, '\0');
16536ac495dSmrg   result = get_identifier (XOBFINISH (&util_obstack, char *));
16636ac495dSmrg   obstack_free (&util_obstack, util_firstobj);
16736ac495dSmrg   return result;
16836ac495dSmrg }
16936ac495dSmrg 
17036ac495dSmrg /* This is used to implement @encode().  */
17136ac495dSmrg tree
objc_build_encode_expr(tree type)17236ac495dSmrg objc_build_encode_expr (tree type)
17336ac495dSmrg {
17436ac495dSmrg   tree result;
17536ac495dSmrg   const char *string;
17636ac495dSmrg 
17736ac495dSmrg   encode_type (type, obstack_object_size (&util_obstack),
17836ac495dSmrg 	       OBJC_ENCODE_INLINE_DEFS);
17936ac495dSmrg   obstack_1grow (&util_obstack, 0);    /* null terminate string */
18036ac495dSmrg   string = XOBFINISH (&util_obstack, const char *);
18136ac495dSmrg 
18236ac495dSmrg   /* Synthesize a string that represents the encoded struct/union.  */
18336ac495dSmrg   result = my_build_string (strlen (string) + 1, string);
18436ac495dSmrg   obstack_free (&util_obstack, util_firstobj);
18536ac495dSmrg   return result;
18636ac495dSmrg }
18736ac495dSmrg 
18836ac495dSmrg /* "Encode" a data type into a string, which grows in util_obstack.
18936ac495dSmrg 
19036ac495dSmrg    The format is described in gcc/doc/objc.texi, section 'Type
19136ac495dSmrg    encoding'.
19236ac495dSmrg 
19336ac495dSmrg    Most of the encode_xxx functions have a 'type' argument, which is
19436ac495dSmrg    the type to encode, and an integer 'curtype' argument, which is the
19536ac495dSmrg    index in the encoding string of the beginning of the encoding of
19636ac495dSmrg    the current type, and allows you to find what characters have
19736ac495dSmrg    already been written for the current type (they are the ones in the
19836ac495dSmrg    current encoding string starting from 'curtype').
19936ac495dSmrg 
20036ac495dSmrg    For example, if we are encoding a method which returns 'int' and
20136ac495dSmrg    takes a 'char **' argument, then when we get to the point of
20236ac495dSmrg    encoding the 'char **' argument, the encoded string already
20336ac495dSmrg    contains 'i12@0:4' (assuming a pointer size of 4 bytes).  So,
20436ac495dSmrg    'curtype' will be set to 7 when starting to encode 'char **'.
20536ac495dSmrg    During the whole of the encoding of 'char **', 'curtype' will be
20636ac495dSmrg    fixed at 7, so the routine encoding the second pointer can find out
20736ac495dSmrg    that it's actually encoding a pointer to a pointer by looking
20836ac495dSmrg    backwards at what has already been encoded for the current type,
20936ac495dSmrg    and seeing there is a "^" (meaning a pointer) in there.  */
21036ac495dSmrg 
21136ac495dSmrg 
21236ac495dSmrg /* Encode type qualifiers encodes one of the "PQ" Objective-C
21336ac495dSmrg    keywords, ie 'in', 'out', 'inout', 'bycopy', 'byref', 'oneway'.
21436ac495dSmrg    'const', instead, is encoded directly as part of the type.  */
21536ac495dSmrg static void
encode_type_qualifiers(tree declspecs)21636ac495dSmrg encode_type_qualifiers (tree declspecs)
21736ac495dSmrg {
21836ac495dSmrg   tree spec;
21936ac495dSmrg 
22036ac495dSmrg   for (spec = declspecs; spec; spec = TREE_CHAIN (spec))
22136ac495dSmrg     {
22236ac495dSmrg       /* FIXME: Shouldn't we use token->keyword here ? */
22336ac495dSmrg       if (ridpointers[(int) RID_IN] == TREE_VALUE (spec))
22436ac495dSmrg 	obstack_1grow (&util_obstack, 'n');
22536ac495dSmrg       else if (ridpointers[(int) RID_INOUT] == TREE_VALUE (spec))
22636ac495dSmrg 	obstack_1grow (&util_obstack, 'N');
22736ac495dSmrg       else if (ridpointers[(int) RID_OUT] == TREE_VALUE (spec))
22836ac495dSmrg 	obstack_1grow (&util_obstack, 'o');
22936ac495dSmrg       else if (ridpointers[(int) RID_BYCOPY] == TREE_VALUE (spec))
23036ac495dSmrg 	obstack_1grow (&util_obstack, 'O');
23136ac495dSmrg       else if (ridpointers[(int) RID_BYREF] == TREE_VALUE (spec))
23236ac495dSmrg         obstack_1grow (&util_obstack, 'R');
23336ac495dSmrg       else if (ridpointers[(int) RID_ONEWAY] == TREE_VALUE (spec))
23436ac495dSmrg 	obstack_1grow (&util_obstack, 'V');
23536ac495dSmrg       else
23636ac495dSmrg 	gcc_unreachable ();
23736ac495dSmrg     }
23836ac495dSmrg }
23936ac495dSmrg 
24036ac495dSmrg /* Determine if a pointee is marked read-only.  Only used by the NeXT
24136ac495dSmrg    runtime to be compatible with gcc-3.3.  */
24236ac495dSmrg static bool
pointee_is_readonly(tree pointee)24336ac495dSmrg pointee_is_readonly (tree pointee)
24436ac495dSmrg {
24536ac495dSmrg   while (POINTER_TYPE_P (pointee))
24636ac495dSmrg     pointee = TREE_TYPE (pointee);
24736ac495dSmrg 
24836ac495dSmrg   return TYPE_READONLY (pointee);
24936ac495dSmrg }
25036ac495dSmrg 
25136ac495dSmrg /* Encode a pointer type.  */
25236ac495dSmrg static void
encode_pointer(tree type,int curtype,int format)25336ac495dSmrg encode_pointer (tree type, int curtype, int format)
25436ac495dSmrg {
25536ac495dSmrg   tree pointer_to = TREE_TYPE (type);
25636ac495dSmrg 
25736ac495dSmrg   if (flag_next_runtime)
25836ac495dSmrg     {
25936ac495dSmrg       /* This code is used to be compatible with gcc-3.3.  */
26036ac495dSmrg       /* For historical/compatibility reasons, the read-only qualifier
26136ac495dSmrg 	 of the pointee gets emitted _before_ the '^'.  The read-only
26236ac495dSmrg 	 qualifier of the pointer itself gets ignored, _unless_ we are
26336ac495dSmrg 	 looking at a typedef!  Also, do not emit the 'r' for anything
26436ac495dSmrg 	 but the outermost type!  */
26536ac495dSmrg       if (!generating_instance_variables
26636ac495dSmrg 	  && (obstack_object_size (&util_obstack) - curtype <= 1)
26736ac495dSmrg 	  && (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
26836ac495dSmrg 	      ? TYPE_READONLY (type)
26936ac495dSmrg 	      : pointee_is_readonly (pointer_to)))
27036ac495dSmrg 	obstack_1grow (&util_obstack, 'r');
27136ac495dSmrg     }
27236ac495dSmrg 
27336ac495dSmrg   if (TREE_CODE (pointer_to) == RECORD_TYPE)
27436ac495dSmrg     {
27536ac495dSmrg       if (OBJC_TYPE_NAME (pointer_to)
27636ac495dSmrg 	  && TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE)
27736ac495dSmrg 	{
27836ac495dSmrg 	  const char *name = IDENTIFIER_POINTER (OBJC_TYPE_NAME (pointer_to));
27936ac495dSmrg 
28036ac495dSmrg 	  if (strcmp (name, TAG_OBJECT) == 0) /* '@' */
28136ac495dSmrg 	    {
28236ac495dSmrg 	      obstack_1grow (&util_obstack, '@');
28336ac495dSmrg 	      return;
28436ac495dSmrg 	    }
28536ac495dSmrg 	  else if (TYPE_HAS_OBJC_INFO (pointer_to)
28636ac495dSmrg 		   && TYPE_OBJC_INTERFACE (pointer_to))
28736ac495dSmrg 	    {
28836ac495dSmrg               if (generating_instance_variables)
28936ac495dSmrg 	        {
29036ac495dSmrg 	          obstack_1grow (&util_obstack, '@');
29136ac495dSmrg 	          obstack_1grow (&util_obstack, '"');
29236ac495dSmrg 	          obstack_grow (&util_obstack, name, strlen (name));
29336ac495dSmrg 	          obstack_1grow (&util_obstack, '"');
29436ac495dSmrg 	          return;
29536ac495dSmrg 		}
29636ac495dSmrg               else
29736ac495dSmrg 	        {
29836ac495dSmrg 	          obstack_1grow (&util_obstack, '@');
29936ac495dSmrg 	          return;
30036ac495dSmrg 		}
30136ac495dSmrg 	    }
30236ac495dSmrg 	  else if (strcmp (name, TAG_CLASS) == 0) /* '#' */
30336ac495dSmrg 	    {
30436ac495dSmrg 	      obstack_1grow (&util_obstack, '#');
30536ac495dSmrg 	      return;
30636ac495dSmrg 	    }
30736ac495dSmrg 	  else if (strcmp (name, TAG_SELECTOR) == 0) /* ':' */
30836ac495dSmrg 	    {
30936ac495dSmrg 	      obstack_1grow (&util_obstack, ':');
31036ac495dSmrg 	      return;
31136ac495dSmrg 	    }
31236ac495dSmrg 	}
31336ac495dSmrg     }
31436ac495dSmrg   else if (TREE_CODE (pointer_to) == INTEGER_TYPE
31536ac495dSmrg 	   && TYPE_MODE (pointer_to) == QImode)
31636ac495dSmrg     {
31736ac495dSmrg       tree pname = TREE_CODE (OBJC_TYPE_NAME (pointer_to)) == IDENTIFIER_NODE
31836ac495dSmrg 	          ? OBJC_TYPE_NAME (pointer_to)
31936ac495dSmrg 	          : DECL_NAME (OBJC_TYPE_NAME (pointer_to));
32036ac495dSmrg 
32136ac495dSmrg       /* (BOOL *) are an exception and are encoded as ^c, while all
32236ac495dSmrg 	 other pointers to char are encoded as *.   */
32336ac495dSmrg       if (strcmp (IDENTIFIER_POINTER (pname), "BOOL"))
32436ac495dSmrg 	{
32536ac495dSmrg 	  if (!flag_next_runtime)
32636ac495dSmrg 	    {
32736ac495dSmrg 	      /* The NeXT runtime adds the 'r' before getting here.  */
32836ac495dSmrg 
32936ac495dSmrg 	      /* It appears that "r*" means "const char *" rather than
33036ac495dSmrg 		 "char *const".  "char *const" is encoded as "*",
33136ac495dSmrg 		 which is identical to "char *", so the "const" is
33236ac495dSmrg 		 unfortunately lost.  */
33336ac495dSmrg 	      if (TYPE_READONLY (pointer_to))
33436ac495dSmrg 		obstack_1grow (&util_obstack, 'r');
33536ac495dSmrg 	    }
33636ac495dSmrg 
33736ac495dSmrg 	  obstack_1grow (&util_obstack, '*');
33836ac495dSmrg 	  return;
33936ac495dSmrg 	}
34036ac495dSmrg     }
34136ac495dSmrg 
34236ac495dSmrg   /* We have a normal pointer type that does not get special treatment.  */
34336ac495dSmrg   obstack_1grow (&util_obstack, '^');
34436ac495dSmrg   encode_type (pointer_to, curtype, format);
34536ac495dSmrg }
34636ac495dSmrg 
34736ac495dSmrg static void
encode_array(tree type,int curtype,int format)34836ac495dSmrg encode_array (tree type, int curtype, int format)
34936ac495dSmrg {
35036ac495dSmrg   tree an_int_cst = TYPE_SIZE (type);
35136ac495dSmrg   tree array_of = TREE_TYPE (type);
35236ac495dSmrg   char buffer[40];
35336ac495dSmrg 
35436ac495dSmrg   if (an_int_cst == NULL)
35536ac495dSmrg     {
35636ac495dSmrg       /* We are trying to encode an incomplete array.  An incomplete
35736ac495dSmrg 	 array is forbidden as part of an instance variable; but it
35836ac495dSmrg 	 may occur if the instance variable is a pointer to such an
35936ac495dSmrg 	 array.  */
36036ac495dSmrg 
36136ac495dSmrg       /* So the only case in which an incomplete array could occur
36236ac495dSmrg 	 (without being pointed to) is if we are encoding the
36336ac495dSmrg 	 arguments or return value of a method.  In that case, an
36436ac495dSmrg 	 incomplete array argument or return value (eg,
36536ac495dSmrg 	 -(void)display: (char[])string) is treated like a pointer
36636ac495dSmrg 	 because that is how the compiler does the function call.  A
36736ac495dSmrg 	 special, more complicated case, is when the incomplete array
36836ac495dSmrg 	 is the last member of a struct (eg, if we are encoding
36936ac495dSmrg 	 "struct { unsigned long int a;double b[];}"), which is again
37036ac495dSmrg 	 part of a method argument/return value.  In that case, we
37136ac495dSmrg 	 really need to communicate to the runtime that there is an
37236ac495dSmrg 	 incomplete array (not a pointer!) there.  So, we detect that
37336ac495dSmrg 	 special case and encode it as a zero-length array.
37436ac495dSmrg 
37536ac495dSmrg 	 Try to detect that we are part of a struct.  We do this by
37636ac495dSmrg 	 searching for '=' in the type encoding for the current type.
37736ac495dSmrg 	 NB: This hack assumes that you can't use '=' as part of a C
37836ac495dSmrg 	 identifier.
37936ac495dSmrg       */
38036ac495dSmrg       {
38136ac495dSmrg 	char *enc = (char *) obstack_base (&util_obstack) + curtype;
38236ac495dSmrg 	if (memchr (enc, '=',
38336ac495dSmrg 		    obstack_object_size (&util_obstack) - curtype) == NULL)
38436ac495dSmrg 	  {
38536ac495dSmrg 	    /* We are not inside a struct.  Encode the array as a
38636ac495dSmrg 	       pointer.  */
38736ac495dSmrg 	    encode_pointer (type, curtype, format);
38836ac495dSmrg 	    return;
38936ac495dSmrg 	  }
39036ac495dSmrg       }
39136ac495dSmrg 
39236ac495dSmrg       /* Else, we are in a struct, and we encode it as a zero-length
39336ac495dSmrg 	 array.  */
39436ac495dSmrg       sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0);
39536ac495dSmrg     }
39636ac495dSmrg   else if (TREE_INT_CST_LOW (TYPE_SIZE (array_of)) == 0)
39736ac495dSmrg    sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0);
39836ac495dSmrg   else
39936ac495dSmrg     sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC,
40036ac495dSmrg 	     TREE_INT_CST_LOW (an_int_cst)
40136ac495dSmrg 	      / TREE_INT_CST_LOW (TYPE_SIZE (array_of)));
40236ac495dSmrg 
40336ac495dSmrg   obstack_grow (&util_obstack, buffer, strlen (buffer));
40436ac495dSmrg   encode_type (array_of, curtype, format);
40536ac495dSmrg   obstack_1grow (&util_obstack, ']');
40636ac495dSmrg   return;
40736ac495dSmrg }
40836ac495dSmrg 
40936ac495dSmrg /* Encode a vector.  The vector type is a GCC extension to C.  */
41036ac495dSmrg static void
encode_vector(tree type,int curtype,int format)41136ac495dSmrg encode_vector (tree type, int curtype, int format)
41236ac495dSmrg {
41336ac495dSmrg   tree vector_of = TREE_TYPE (type);
41436ac495dSmrg   char buffer[40];
41536ac495dSmrg 
41636ac495dSmrg   /* Vectors are like simple fixed-size arrays.  */
41736ac495dSmrg 
41836ac495dSmrg   /* Output ![xx,yy,<code>] where xx is the vector_size, yy is the
41936ac495dSmrg      alignment of the vector, and <code> is the base type.  Eg, int
42036ac495dSmrg      __attribute__ ((vector_size (16))) gets encoded as ![16,32,i]
42136ac495dSmrg      assuming that the alignment is 32 bytes.  We include size and
42236ac495dSmrg      alignment in bytes so that the runtime does not have to have any
42336ac495dSmrg      knowledge of the actual types.
42436ac495dSmrg   */
42536ac495dSmrg   sprintf (buffer, "![" HOST_WIDE_INT_PRINT_DEC ",%d",
42636ac495dSmrg 	   /* We want to compute the equivalent of sizeof (<vector>).
42736ac495dSmrg 	      Code inspired by c_sizeof_or_alignof_type.  */
42836ac495dSmrg 	   ((TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type))
42936ac495dSmrg 	     / (TYPE_PRECISION (char_type_node) / BITS_PER_UNIT))),
43036ac495dSmrg 	   /* We want to compute the equivalent of __alignof__
43136ac495dSmrg 	      (<vector>).  Code inspired by
43236ac495dSmrg 	      c_sizeof_or_alignof_type.  */
43336ac495dSmrg 	   TYPE_ALIGN_UNIT (type));
43436ac495dSmrg   obstack_grow (&util_obstack, buffer, strlen (buffer));
43536ac495dSmrg   encode_type (vector_of, curtype, format);
43636ac495dSmrg   obstack_1grow (&util_obstack, ']');
43736ac495dSmrg   return;
43836ac495dSmrg }
43936ac495dSmrg 
44036ac495dSmrg static void
encode_aggregate_fields(tree type,bool pointed_to,int curtype,int format)44136ac495dSmrg encode_aggregate_fields (tree type, bool pointed_to, int curtype, int format)
44236ac495dSmrg {
44336ac495dSmrg   tree field = TYPE_FIELDS (type);
44436ac495dSmrg 
44536ac495dSmrg   for (; field; field = DECL_CHAIN (field))
44636ac495dSmrg     {
44736ac495dSmrg #ifdef OBJCPLUS
44836ac495dSmrg       /* C++ static members, and things that are not field at all,
44936ac495dSmrg 	 should not appear in the encoding.  */
45036ac495dSmrg       if (TREE_CODE (field) != FIELD_DECL || TREE_STATIC (field))
45136ac495dSmrg 	continue;
45236ac495dSmrg #endif
45336ac495dSmrg 
45436ac495dSmrg       /* Recursively encode fields of embedded base classes.  */
45536ac495dSmrg       if (DECL_ARTIFICIAL (field) && !DECL_NAME (field)
45636ac495dSmrg 	  && TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
45736ac495dSmrg 	{
45836ac495dSmrg 	  encode_aggregate_fields (TREE_TYPE (field),
45936ac495dSmrg 				   pointed_to, curtype, format);
46036ac495dSmrg 	  continue;
46136ac495dSmrg 	}
46236ac495dSmrg 
46336ac495dSmrg       if (generating_instance_variables && !pointed_to)
46436ac495dSmrg 	{
46536ac495dSmrg 	  tree fname = DECL_NAME (field);
46636ac495dSmrg 
46736ac495dSmrg 	  obstack_1grow (&util_obstack, '"');
46836ac495dSmrg 
46936ac495dSmrg 	  if (fname && TREE_CODE (fname) == IDENTIFIER_NODE)
47036ac495dSmrg 	    obstack_grow (&util_obstack,
47136ac495dSmrg 			  IDENTIFIER_POINTER (fname),
47236ac495dSmrg 			  strlen (IDENTIFIER_POINTER (fname)));
47336ac495dSmrg 
47436ac495dSmrg 	  obstack_1grow (&util_obstack, '"');
47536ac495dSmrg         }
47636ac495dSmrg 
47736ac495dSmrg       encode_field (field, curtype, format);
47836ac495dSmrg     }
47936ac495dSmrg }
48036ac495dSmrg 
48136ac495dSmrg static void
encode_aggregate_within(tree type,int curtype,int format,int left,int right)48236ac495dSmrg encode_aggregate_within (tree type, int curtype, int format, int left,
48336ac495dSmrg 			 int right)
48436ac495dSmrg {
48536ac495dSmrg   tree name;
48636ac495dSmrg   /* NB: aggregates that are pointed to have slightly different encoding
48736ac495dSmrg      rules in that you never encode the names of instance variables.  */
48836ac495dSmrg   int ob_size = obstack_object_size (&util_obstack);
48936ac495dSmrg   bool inline_contents = false;
49036ac495dSmrg   bool pointed_to = false;
49136ac495dSmrg 
49236ac495dSmrg   if (flag_next_runtime)
49336ac495dSmrg     {
49436ac495dSmrg       if (ob_size > 0
49536ac495dSmrg 	  && *((char *) obstack_next_free (&util_obstack) - 1) == '^')
49636ac495dSmrg 	pointed_to = true;
49736ac495dSmrg 
49836ac495dSmrg       if ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables)
49936ac495dSmrg 	  && (!pointed_to || ob_size - curtype == 1
50036ac495dSmrg 	      || (ob_size - curtype == 2
50136ac495dSmrg 		  && *((char *) obstack_next_free (&util_obstack) - 2) == 'r')))
50236ac495dSmrg 	inline_contents = true;
50336ac495dSmrg     }
50436ac495dSmrg   else
50536ac495dSmrg     {
50636ac495dSmrg       /* c0 and c1 are the last two characters in the encoding of the
50736ac495dSmrg 	 current type; if the last two characters were '^' or '^r',
50836ac495dSmrg 	 then we are encoding an aggregate that is "pointed to".  The
50936ac495dSmrg 	 comment above applies: in that case we should avoid encoding
51036ac495dSmrg 	 the names of instance variables.
51136ac495dSmrg       */
51236ac495dSmrg       char c0, c1;
51336ac495dSmrg 
51436ac495dSmrg       c1 = ob_size > 1 ? *((char *) obstack_next_free (&util_obstack) - 2) : 0;
51536ac495dSmrg       c0 = ob_size > 0 ? *((char *) obstack_next_free (&util_obstack) - 1) : 0;
51636ac495dSmrg       if (c0 == '^' || (c1 == '^' && c0 == 'r'))
51736ac495dSmrg 	pointed_to = true;
51836ac495dSmrg 
51936ac495dSmrg       if (format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables)
52036ac495dSmrg 	{
52136ac495dSmrg 	  if (!pointed_to)
52236ac495dSmrg 	    inline_contents = true;
52336ac495dSmrg 	  else
52436ac495dSmrg 	    {
52536ac495dSmrg 	      /* Note that the check (ob_size - curtype < 2) prevents
52636ac495dSmrg 		 infinite recursion when encoding a structure which is
52736ac495dSmrg 		 a linked list (eg, struct node { struct node *next;
52836ac495dSmrg 		 }).  Each time we follow a pointer, we add one
52936ac495dSmrg 		 character to ob_size, and curtype is fixed, so after
53036ac495dSmrg 		 at most two pointers we stop inlining contents and
53136ac495dSmrg 		 break the loop.
53236ac495dSmrg 
53336ac495dSmrg 		 The other case where we don't inline is "^r", which
53436ac495dSmrg 		 is a pointer to a constant struct.
53536ac495dSmrg 	      */
53636ac495dSmrg 	      if ((ob_size - curtype <= 2) && !(c0 == 'r'))
53736ac495dSmrg 		inline_contents = true;
53836ac495dSmrg 	    }
53936ac495dSmrg 	}
54036ac495dSmrg     }
54136ac495dSmrg 
54236ac495dSmrg   /* Traverse struct aliases; it is important to get the
54336ac495dSmrg      original struct and its tag name (if any).  */
54436ac495dSmrg   type = TYPE_MAIN_VARIANT (type);
54536ac495dSmrg   name = OBJC_TYPE_NAME (type);
54636ac495dSmrg   /* Open parenth/bracket.  */
54736ac495dSmrg   obstack_1grow (&util_obstack, left);
54836ac495dSmrg 
54936ac495dSmrg   /* Encode the struct/union tag name, or '?' if a tag was
55036ac495dSmrg      not provided.  Typedef aliases do not qualify.  */
55136ac495dSmrg #ifdef OBJCPLUS
55236ac495dSmrg   /* For compatibility with the NeXT runtime, ObjC++ encodes template
55336ac495dSmrg      args as a composite struct tag name. */
55436ac495dSmrg   if (name && TREE_CODE (name) == IDENTIFIER_NODE
55536ac495dSmrg       /* Did this struct have a tag?  */
55636ac495dSmrg       && !TYPE_WAS_UNNAMED (type))
55736ac495dSmrg     obstack_grow (&util_obstack,
55836ac495dSmrg 		  decl_as_string (type, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME),
55936ac495dSmrg 		  strlen (decl_as_string (type, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME)));
56036ac495dSmrg #else
56136ac495dSmrg   if (name && TREE_CODE (name) == IDENTIFIER_NODE)
56236ac495dSmrg     obstack_grow (&util_obstack,
56336ac495dSmrg 		  IDENTIFIER_POINTER (name),
56436ac495dSmrg 		  strlen (IDENTIFIER_POINTER (name)));
56536ac495dSmrg #endif
56636ac495dSmrg   else
56736ac495dSmrg     obstack_1grow (&util_obstack, '?');
56836ac495dSmrg 
56936ac495dSmrg   /* Encode the types (and possibly names) of the inner fields,
57036ac495dSmrg      if required.  */
57136ac495dSmrg   if (inline_contents)
57236ac495dSmrg     {
57336ac495dSmrg       obstack_1grow (&util_obstack, '=');
57436ac495dSmrg       encode_aggregate_fields (type, pointed_to, curtype, format);
57536ac495dSmrg     }
57636ac495dSmrg   /* Close parenth/bracket.  */
57736ac495dSmrg   obstack_1grow (&util_obstack, right);
57836ac495dSmrg }
57936ac495dSmrg 
58036ac495dSmrg /* Encode a bitfield NeXT-style (i.e., without a bit offset or the underlying
58136ac495dSmrg    field type.  */
58236ac495dSmrg static void
encode_next_bitfield(int width)58336ac495dSmrg encode_next_bitfield (int width)
58436ac495dSmrg {
58536ac495dSmrg   char buffer[40];
58636ac495dSmrg   sprintf (buffer, "b%d", width);
58736ac495dSmrg   obstack_grow (&util_obstack, buffer, strlen (buffer));
58836ac495dSmrg }
58936ac495dSmrg 
59036ac495dSmrg /* Encodes 'type', ignoring type qualifiers (which you should encode
59136ac495dSmrg    beforehand if needed) with the exception of 'const', which is
59236ac495dSmrg    encoded by encode_type.  See above for the explanation of
59336ac495dSmrg    'curtype'.  'format' can be OBJC_ENCODE_INLINE_DEFS or
59436ac495dSmrg    OBJC_ENCODE_DONT_INLINE_DEFS.  */
59536ac495dSmrg static void
encode_type(tree type,int curtype,int format)59636ac495dSmrg encode_type (tree type, int curtype, int format)
59736ac495dSmrg {
59836ac495dSmrg   enum tree_code code = TREE_CODE (type);
59936ac495dSmrg 
60036ac495dSmrg   /* Ignore type qualifiers other than 'const' when encoding a
60136ac495dSmrg      type.  */
60236ac495dSmrg 
60336ac495dSmrg   if (type == error_mark_node)
60436ac495dSmrg     return;
60536ac495dSmrg 
60636ac495dSmrg   if (!flag_next_runtime)
60736ac495dSmrg     {
60836ac495dSmrg       if (TYPE_READONLY (type))
60936ac495dSmrg 	obstack_1grow (&util_obstack, 'r');
61036ac495dSmrg     }
61136ac495dSmrg 
61236ac495dSmrg   switch (code)
61336ac495dSmrg     {
61436ac495dSmrg     case ENUMERAL_TYPE:
61536ac495dSmrg       if (flag_next_runtime)
61636ac495dSmrg 	{
61736ac495dSmrg 	  /* Kludge for backwards-compatibility with gcc-3.3: enums
61836ac495dSmrg 	     are always encoded as 'i' no matter what type they
61936ac495dSmrg 	     actually are (!).  */
62036ac495dSmrg 	  obstack_1grow (&util_obstack, 'i');
62136ac495dSmrg 	  break;
62236ac495dSmrg 	}
62336ac495dSmrg       /* Else, they are encoded exactly like the integer type that is
62436ac495dSmrg 	 used by the compiler to store them.  */
62536ac495dSmrg       /* FALLTHRU */
62636ac495dSmrg     case INTEGER_TYPE:
62736ac495dSmrg       {
62836ac495dSmrg 	char c;
629a2dc1f3fSmrg 	switch (GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (type)))
63036ac495dSmrg 	  {
63136ac495dSmrg 	  case 8:  c = TYPE_UNSIGNED (type) ? 'C' : 'c'; break;
63236ac495dSmrg 	  case 16: c = TYPE_UNSIGNED (type) ? 'S' : 's'; break;
63336ac495dSmrg 	  case 32:
63436ac495dSmrg 	    {
63536ac495dSmrg 	      tree int_type = type;
63636ac495dSmrg 	      if (flag_next_runtime)
63736ac495dSmrg 		{
63836ac495dSmrg 		  /* Another legacy kludge for compatibility with
63936ac495dSmrg 		     gcc-3.3: 32-bit longs are encoded as 'l' or 'L',
64036ac495dSmrg 		     but not always.  For typedefs, we need to use 'i'
64136ac495dSmrg 		     or 'I' instead if encoding a struct field, or a
64236ac495dSmrg 		     pointer!  */
64336ac495dSmrg 		  int_type =  ((!generating_instance_variables
64436ac495dSmrg 				&& (obstack_object_size (&util_obstack)
64536ac495dSmrg 				    == (unsigned) curtype))
64636ac495dSmrg 			       ? TYPE_MAIN_VARIANT (type)
64736ac495dSmrg 			       : type);
64836ac495dSmrg 		}
64936ac495dSmrg 	      if (int_type == long_unsigned_type_node
65036ac495dSmrg 		  || int_type == long_integer_type_node)
65136ac495dSmrg 		c = TYPE_UNSIGNED (type) ? 'L' : 'l';
65236ac495dSmrg 	      else
65336ac495dSmrg 		c = TYPE_UNSIGNED (type) ? 'I' : 'i';
65436ac495dSmrg 	    }
65536ac495dSmrg 	    break;
65636ac495dSmrg 	  case 64:  c = TYPE_UNSIGNED (type) ? 'Q' : 'q'; break;
65736ac495dSmrg 	  case 128: c = TYPE_UNSIGNED (type) ? 'T' : 't'; break;
65836ac495dSmrg 	  default: gcc_unreachable ();
65936ac495dSmrg 	  }
66036ac495dSmrg 	obstack_1grow (&util_obstack, c);
66136ac495dSmrg 	break;
66236ac495dSmrg       }
66336ac495dSmrg     case REAL_TYPE:
66436ac495dSmrg       {
66536ac495dSmrg 	char c;
66636ac495dSmrg 	/* Floating point types.  */
667a2dc1f3fSmrg 	switch (GET_MODE_BITSIZE (SCALAR_FLOAT_TYPE_MODE (type)))
66836ac495dSmrg 	  {
66936ac495dSmrg 	  case 32:  c = 'f'; break;
67036ac495dSmrg 	  case 64:  c = 'd'; break;
67136ac495dSmrg 	  case 96:
67236ac495dSmrg 	  case 128: c = 'D'; break;
67336ac495dSmrg 	  default: gcc_unreachable ();
67436ac495dSmrg 	  }
67536ac495dSmrg 	obstack_1grow (&util_obstack, c);
67636ac495dSmrg 	break;
67736ac495dSmrg       }
67836ac495dSmrg     case VOID_TYPE:
67936ac495dSmrg       obstack_1grow (&util_obstack, 'v');
68036ac495dSmrg       break;
68136ac495dSmrg 
68236ac495dSmrg     case BOOLEAN_TYPE:
68336ac495dSmrg       obstack_1grow (&util_obstack, 'B');
68436ac495dSmrg       break;
68536ac495dSmrg 
68636ac495dSmrg     case ARRAY_TYPE:
68736ac495dSmrg       encode_array (type, curtype, format);
68836ac495dSmrg       break;
68936ac495dSmrg 
69036ac495dSmrg     case POINTER_TYPE:
69136ac495dSmrg #ifdef OBJCPLUS
69236ac495dSmrg     case REFERENCE_TYPE:
69336ac495dSmrg #endif
69436ac495dSmrg       encode_pointer (type, curtype, format);
69536ac495dSmrg       break;
69636ac495dSmrg 
69736ac495dSmrg     case RECORD_TYPE:
69836ac495dSmrg       encode_aggregate_within (type, curtype, format, '{', '}');
69936ac495dSmrg       break;
70036ac495dSmrg 
70136ac495dSmrg     case UNION_TYPE:
70236ac495dSmrg       encode_aggregate_within (type, curtype, format, '(', ')');
70336ac495dSmrg       break;
70436ac495dSmrg 
70536ac495dSmrg     case FUNCTION_TYPE: /* '?' means an unknown type.  */
70636ac495dSmrg       obstack_1grow (&util_obstack, '?');
70736ac495dSmrg       break;
70836ac495dSmrg 
70936ac495dSmrg     case COMPLEX_TYPE:
71036ac495dSmrg       /* A complex is encoded as 'j' followed by the inner type (eg,
71136ac495dSmrg 	 "_Complex int" is encoded as 'ji').  */
71236ac495dSmrg       obstack_1grow (&util_obstack, 'j');
71336ac495dSmrg       encode_type (TREE_TYPE (type), curtype, format);
71436ac495dSmrg       break;
71536ac495dSmrg 
71636ac495dSmrg     case VECTOR_TYPE:
71736ac495dSmrg       encode_vector (type, curtype, format);
71836ac495dSmrg       break;
71936ac495dSmrg 
72036ac495dSmrg     default:
72136ac495dSmrg       warning (0, "unknown type %<%T%> found during Objective-C encoding",
72236ac495dSmrg 	       TREE_TYPE (type));
72336ac495dSmrg       obstack_1grow (&util_obstack, '?');
72436ac495dSmrg       break;
72536ac495dSmrg     }
72636ac495dSmrg 
72736ac495dSmrg   if (flag_next_runtime)
72836ac495dSmrg     {
72936ac495dSmrg       /* Super-kludge.  Some ObjC qualifier and type combinations need
73036ac495dSmrg 	 to be rearranged for compatibility with gcc-3.3.  */
73136ac495dSmrg       if (code == POINTER_TYPE && obstack_object_size (&util_obstack) >= 3)
73236ac495dSmrg 	{
73336ac495dSmrg 	  char *enc = (char *) obstack_base (&util_obstack) + curtype;
73436ac495dSmrg 
73536ac495dSmrg 	  /* Rewrite "in const" from "nr" to "rn".  */
73636ac495dSmrg 	  if (curtype >= 1 && !strncmp (enc - 1, "nr", 2))
737a2dc1f3fSmrg 	    memcpy (enc - 1, "rn", 2);
73836ac495dSmrg 	}
73936ac495dSmrg     }
74036ac495dSmrg }
74136ac495dSmrg 
74236ac495dSmrg static void
encode_gnu_bitfield(int position,tree type,int size)74336ac495dSmrg encode_gnu_bitfield (int position, tree type, int size)
74436ac495dSmrg {
74536ac495dSmrg   enum tree_code code = TREE_CODE (type);
74636ac495dSmrg   char buffer[40];
74736ac495dSmrg   char charType = '?';
74836ac495dSmrg 
74936ac495dSmrg   /* This code is only executed for the GNU runtime, so we can ignore
75036ac495dSmrg      the NeXT runtime kludge of always encoding enums as 'i' no matter
75136ac495dSmrg      what integers they actually are.  */
75236ac495dSmrg   if (code == INTEGER_TYPE  ||  code == ENUMERAL_TYPE)
75336ac495dSmrg     {
75436ac495dSmrg       if (integer_zerop (TYPE_MIN_VALUE (type)))
75536ac495dSmrg 	/* Unsigned integer types.  */
75636ac495dSmrg 	{
75736ac495dSmrg 	  switch (TYPE_MODE (type))
75836ac495dSmrg 	    {
759a2dc1f3fSmrg 	    case E_QImode:
76036ac495dSmrg 	      charType = 'C'; break;
761a2dc1f3fSmrg 	    case E_HImode:
76236ac495dSmrg 	      charType = 'S'; break;
763a2dc1f3fSmrg 	    case E_SImode:
76436ac495dSmrg 	      {
76536ac495dSmrg 		if (type == long_unsigned_type_node)
76636ac495dSmrg 		  charType = 'L';
76736ac495dSmrg 		else
76836ac495dSmrg 		  charType = 'I';
76936ac495dSmrg 		break;
77036ac495dSmrg 	      }
771a2dc1f3fSmrg 	    case E_DImode:
77236ac495dSmrg 	      charType = 'Q'; break;
77336ac495dSmrg 	    default:
77436ac495dSmrg 	      gcc_unreachable ();
77536ac495dSmrg 	    }
77636ac495dSmrg 	}
77736ac495dSmrg       else
77836ac495dSmrg 	/* Signed integer types.  */
77936ac495dSmrg 	{
78036ac495dSmrg 	  switch (TYPE_MODE (type))
78136ac495dSmrg 	    {
782a2dc1f3fSmrg 	    case E_QImode:
78336ac495dSmrg 	      charType = 'c'; break;
784a2dc1f3fSmrg 	    case E_HImode:
78536ac495dSmrg 	      charType = 's'; break;
786a2dc1f3fSmrg 	    case E_SImode:
78736ac495dSmrg 	      {
78836ac495dSmrg 		if (type == long_integer_type_node)
78936ac495dSmrg 		  charType = 'l';
79036ac495dSmrg 		else
79136ac495dSmrg 		  charType = 'i';
79236ac495dSmrg 		break;
79336ac495dSmrg 	      }
794a2dc1f3fSmrg 	    case E_DImode:
79536ac495dSmrg 	      charType = 'q'; break;
79636ac495dSmrg 	    default:
79736ac495dSmrg 	      gcc_unreachable ();
79836ac495dSmrg 	    }
79936ac495dSmrg 	}
80036ac495dSmrg     }
80136ac495dSmrg   else
80236ac495dSmrg     {
80336ac495dSmrg       /* Do not do any encoding, produce an error and keep going.  */
804*8feb0f0bSmrg       error ("trying to encode non-integer type as a bit-field");
80536ac495dSmrg       return;
80636ac495dSmrg     }
80736ac495dSmrg 
80836ac495dSmrg   sprintf (buffer, "b%d%c%d", position, charType, size);
80936ac495dSmrg   obstack_grow (&util_obstack, buffer, strlen (buffer));
81036ac495dSmrg }
81136ac495dSmrg 
81236ac495dSmrg static void
encode_field(tree field_decl,int curtype,int format)81336ac495dSmrg encode_field (tree field_decl, int curtype, int format)
81436ac495dSmrg {
81536ac495dSmrg #ifdef OBJCPLUS
81636ac495dSmrg   /* C++ static members, and things that are not fields at all,
81736ac495dSmrg      should not appear in the encoding.  */
81836ac495dSmrg   if (TREE_CODE (field_decl) != FIELD_DECL || TREE_STATIC (field_decl))
81936ac495dSmrg     return;
82036ac495dSmrg #endif
82136ac495dSmrg 
82236ac495dSmrg   /* Generate the bitfield typing information, if needed.  Note the difference
82336ac495dSmrg      between GNU and NeXT runtimes.  */
82436ac495dSmrg   if (DECL_BIT_FIELD_TYPE (field_decl))
82536ac495dSmrg     {
82636ac495dSmrg       int size = tree_to_uhwi (DECL_SIZE (field_decl));
82736ac495dSmrg 
82836ac495dSmrg       if (flag_next_runtime)
82936ac495dSmrg 	encode_next_bitfield (size);
83036ac495dSmrg       else
83136ac495dSmrg 	encode_gnu_bitfield (int_bit_position (field_decl),
83236ac495dSmrg 			     DECL_BIT_FIELD_TYPE (field_decl), size);
83336ac495dSmrg     }
83436ac495dSmrg   else
83536ac495dSmrg     encode_type (TREE_TYPE (field_decl), curtype, format);
83636ac495dSmrg }
83736ac495dSmrg 
83836ac495dSmrg tree
encode_field_decl(tree field_decl)83936ac495dSmrg encode_field_decl (tree field_decl)
84036ac495dSmrg {
84136ac495dSmrg   tree result;
84236ac495dSmrg 
84336ac495dSmrg   encode_field (field_decl,
84436ac495dSmrg 		obstack_object_size (&util_obstack),
84536ac495dSmrg 		OBJC_ENCODE_DONT_INLINE_DEFS);
84636ac495dSmrg 
84736ac495dSmrg   /* Null terminate string.  */
84836ac495dSmrg   obstack_1grow (&util_obstack, 0);
84936ac495dSmrg 
85036ac495dSmrg   /* Get identifier for the string.  */
85136ac495dSmrg   result = get_identifier (XOBFINISH (&util_obstack, char *));
85236ac495dSmrg   obstack_free (&util_obstack, util_firstobj);
85336ac495dSmrg 
85436ac495dSmrg   return result;
85536ac495dSmrg }
85636ac495dSmrg 
85736ac495dSmrg /* This routine encodes the attribute of the input PROPERTY according
85836ac495dSmrg    to following formula:
85936ac495dSmrg 
86036ac495dSmrg    Property attributes are stored as a comma-delimited C string.
86136ac495dSmrg    Simple attributes such as readonly are encoded as single
86236ac495dSmrg    character. The parametrized attributes, getter=name and
86336ac495dSmrg    setter=name, are encoded as a single character followed by an
86436ac495dSmrg    identifier.  Property types are also encoded as a parametrized
86536ac495dSmrg    attribute.  The characters used to encode these attributes are
86636ac495dSmrg    defined by the following enumeration:
86736ac495dSmrg 
86836ac495dSmrg    enum PropertyAttributes {
86936ac495dSmrg      kPropertyReadOnly = 'R',
87036ac495dSmrg      kPropertyBycopy = 'C',
87136ac495dSmrg      kPropertyByref = '&',
87236ac495dSmrg      kPropertyDynamic = 'D',
87336ac495dSmrg      kPropertyGetter = 'G',
87436ac495dSmrg      kPropertySetter = 'S',
87536ac495dSmrg      kPropertyInstanceVariable = 'V',
87636ac495dSmrg      kPropertyType = 'T',
87736ac495dSmrg      kPropertyWeak = 'W',
87836ac495dSmrg      kPropertyStrong = 'P',
87936ac495dSmrg      kPropertyNonAtomic = 'N'
88036ac495dSmrg    };  */
88136ac495dSmrg tree
objc_v2_encode_prop_attr(tree property)88236ac495dSmrg objc_v2_encode_prop_attr (tree property)
88336ac495dSmrg {
88436ac495dSmrg   const char *string;
88536ac495dSmrg   tree type = TREE_TYPE (property);
88636ac495dSmrg 
88736ac495dSmrg   obstack_1grow (&util_obstack, 'T');
88836ac495dSmrg   encode_type (type, obstack_object_size (&util_obstack),
88936ac495dSmrg 	       OBJC_ENCODE_INLINE_DEFS);
89036ac495dSmrg 
89136ac495dSmrg   if (PROPERTY_READONLY (property))
89236ac495dSmrg     obstack_grow (&util_obstack, ",R", 2);
89336ac495dSmrg 
89436ac495dSmrg   switch (PROPERTY_ASSIGN_SEMANTICS (property))
89536ac495dSmrg     {
89636ac495dSmrg     case OBJC_PROPERTY_COPY:
89736ac495dSmrg       obstack_grow (&util_obstack, ",C", 2);
89836ac495dSmrg       break;
89936ac495dSmrg     case OBJC_PROPERTY_RETAIN:
90036ac495dSmrg       obstack_grow (&util_obstack, ",&", 2);
90136ac495dSmrg       break;
90236ac495dSmrg     case OBJC_PROPERTY_ASSIGN:
90336ac495dSmrg     default:
90436ac495dSmrg       break;
90536ac495dSmrg     }
90636ac495dSmrg 
90736ac495dSmrg   if (PROPERTY_DYNAMIC (property))
90836ac495dSmrg     obstack_grow (&util_obstack, ",D", 2);
90936ac495dSmrg 
91036ac495dSmrg   if (PROPERTY_NONATOMIC (property))
91136ac495dSmrg     obstack_grow (&util_obstack, ",N", 2);
91236ac495dSmrg 
91336ac495dSmrg   /* Here we want to encode the getter name, but only if it's not the
91436ac495dSmrg      standard one.  */
91536ac495dSmrg   if (PROPERTY_GETTER_NAME (property) != PROPERTY_NAME (property))
91636ac495dSmrg     {
91736ac495dSmrg       obstack_grow (&util_obstack, ",G", 2);
91836ac495dSmrg       string = IDENTIFIER_POINTER (PROPERTY_GETTER_NAME (property));
91936ac495dSmrg       obstack_grow (&util_obstack, string, strlen (string));
92036ac495dSmrg     }
92136ac495dSmrg 
92236ac495dSmrg   if (!PROPERTY_READONLY (property))
92336ac495dSmrg     {
92436ac495dSmrg       /* Here we want to encode the setter name, but only if it's not
92536ac495dSmrg 	 the standard one.  */
92636ac495dSmrg       tree standard_setter = get_identifier (objc_build_property_setter_name (PROPERTY_NAME (property)));
92736ac495dSmrg       if (PROPERTY_SETTER_NAME (property) != standard_setter)
92836ac495dSmrg 	{
92936ac495dSmrg 	  obstack_grow (&util_obstack, ",S", 2);
93036ac495dSmrg 	  string = IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (property));
93136ac495dSmrg 	  obstack_grow (&util_obstack, string, strlen (string));
93236ac495dSmrg 	}
93336ac495dSmrg     }
93436ac495dSmrg 
93536ac495dSmrg   /* TODO: Encode strong ('P'), weak ('W') for garbage collection.  */
93636ac495dSmrg 
93736ac495dSmrg   if (!PROPERTY_DYNAMIC (property))
93836ac495dSmrg     {
93936ac495dSmrg       obstack_grow (&util_obstack, ",V", 2);
94036ac495dSmrg       if (PROPERTY_IVAR_NAME (property))
94136ac495dSmrg 	string = IDENTIFIER_POINTER (PROPERTY_IVAR_NAME (property));
94236ac495dSmrg       else
94336ac495dSmrg 	string = IDENTIFIER_POINTER (PROPERTY_NAME (property));
94436ac495dSmrg       obstack_grow (&util_obstack, string, strlen (string));
94536ac495dSmrg     }
94636ac495dSmrg 
94736ac495dSmrg   /* NULL-terminate string.  */
94836ac495dSmrg   obstack_1grow (&util_obstack, 0);
94936ac495dSmrg   string = XOBFINISH (&util_obstack, char *);
95036ac495dSmrg   obstack_free (&util_obstack, util_firstobj);
95136ac495dSmrg   return get_identifier (string);
95236ac495dSmrg }
953