summaryrefslogtreecommitdiff
path: root/gcc/objc/objc-act.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/objc/objc-act.c')
-rw-r--r--gcc/objc/objc-act.c447
1 files changed, 349 insertions, 98 deletions
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index 5d76596479c..101f9fce0c9 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -4434,6 +4434,11 @@ objc_encoded_type_size (tree type)
return sz;
}
+/* Encode a method prototype.
+
+ The format is described in gcc/doc/objc.texi, section 'Method
+ signatures'.
+ */
static tree
encode_method_prototype (tree method_decl)
{
@@ -6796,6 +6801,8 @@ objc_build_selector_expr (location_t loc, tree selnamelist)
return build_selector_reference (loc, selname);
}
+/* This is used to implement @encode(). See gcc/doc/objc.texi,
+ section '@encode'. */
tree
objc_build_encode_expr (tree type)
{
@@ -7931,7 +7938,34 @@ start_protocol (enum tree_code code, tree name, tree list)
/* "Encode" a data type into a string, which grows in util_obstack.
- ??? What is the FORMAT? Someone please document this! */
+
+ The format is described in gcc/doc/objc.texi, section 'Type
+ encoding'.
+
+ Most of the encode_xxx functions have a 'type' argument, which is
+ the type to encode, and an integer 'curtype' argument, which is the
+ index in the encoding string of the beginning of the encoding of
+ the current type, and allows you to find what characters have
+ already been written for the current type (they are the ones in the
+ current encoding string starting from 'curtype').
+
+ For example, if we are encoding a method which returns 'int' and
+ takes a 'char **' argument, then when we get to the point of
+ encoding the 'char **' argument, the encoded string already
+ contains 'i12@0:4' (assuming a pointer size of 4 bytes). So,
+ 'curtype' will be set to 7 when starting to encode 'char **'.
+ During the whole of the encoding of 'char **', 'curtype' will be
+ fixed at 7, so the routine encoding the second pointer can find out
+ that it's actually encoding a pointer to a pointer by looking
+ backwards at what has already been encoded for the current type,
+ and seeing there is a "^" (meaning a pointer) in there.
+*/
+
+
+/* Encode type qualifiers encodes one of the "PQ" Objective-C
+ keywords, ie 'in', 'out', 'inout', 'bycopy', 'byref', 'oneway'.
+ 'const', instead, is encoded directly as part of the type.
+ */
static void
encode_type_qualifiers (tree declspecs)
@@ -7940,6 +7974,7 @@ encode_type_qualifiers (tree declspecs)
for (spec = declspecs; spec; spec = TREE_CHAIN (spec))
{
+ /* FIXME: Shouldn't we use token->keyword here ? */
if (ridpointers[(int) RID_IN] == TREE_VALUE (spec))
obstack_1grow (&util_obstack, 'n');
else if (ridpointers[(int) RID_INOUT] == TREE_VALUE (spec))
@@ -7955,6 +7990,18 @@ encode_type_qualifiers (tree declspecs)
}
}
+/* Determine if a pointee is marked read-only. Only used by the NeXT
+ runtime to be compatible with gcc-3.3. */
+
+static bool
+pointee_is_readonly (tree pointee)
+{
+ while (POINTER_TYPE_P (pointee))
+ pointee = TREE_TYPE (pointee);
+
+ return TYPE_READONLY (pointee);
+}
+
/* Encode a pointer type. */
static void
@@ -7962,6 +8009,22 @@ encode_pointer (tree type, int curtype, int format)
{
tree pointer_to = TREE_TYPE (type);
+ if (flag_next_runtime)
+ {
+ /* This code is used to be compatible with gcc-3.3. */
+ /* For historical/compatibility reasons, the read-only qualifier
+ of the pointee gets emitted _before_ the '^'. The read-only
+ qualifier of the pointer itself gets ignored, _unless_ we are
+ looking at a typedef! Also, do not emit the 'r' for anything
+ but the outermost type! */
+ if (!generating_instance_variables
+ && (obstack_object_size (&util_obstack) - curtype <= 1)
+ && (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ ? TYPE_READONLY (type)
+ : pointee_is_readonly (pointer_to)))
+ obstack_1grow (&util_obstack, 'r');
+ }
+
if (TREE_CODE (pointer_to) == RECORD_TYPE)
{
if (OBJC_TYPE_NAME (pointer_to)
@@ -8010,21 +8073,28 @@ encode_pointer (tree type, int curtype, int format)
? OBJC_TYPE_NAME (pointer_to)
: DECL_NAME (OBJC_TYPE_NAME (pointer_to));
- if (!flag_next_runtime || strcmp (IDENTIFIER_POINTER (pname), "BOOL"))
+ /* (BOOL *) are an exception and are encoded as ^c, while all
+ other pointers to char are encoded as *. */
+ if (strcmp (IDENTIFIER_POINTER (pname), "BOOL"))
{
- /* It appears that "r*" means "const char *" rather than
- "char *const". */
- if (TYPE_READONLY (pointer_to))
- obstack_1grow (&util_obstack, 'r');
+ if (!flag_next_runtime)
+ {
+ /* The NeXT runtime adds the 'r' before getting here. */
+
+ /* It appears that "r*" means "const char *" rather than
+ "char *const". "char *const" is encoded as "*",
+ which is identical to "char *", so the "const" is
+ unfortunately lost. */
+ if (TYPE_READONLY (pointer_to))
+ obstack_1grow (&util_obstack, 'r');
+ }
obstack_1grow (&util_obstack, '*');
return;
}
}
- /* We have a type that does not get special treatment. */
-
- /* NeXT extension */
+ /* We have a normal pointer type that does not get special treatment. */
obstack_1grow (&util_obstack, '^');
encode_type (pointer_to, curtype, format);
}
@@ -8036,14 +8106,51 @@ encode_array (tree type, int curtype, int format)
tree array_of = TREE_TYPE (type);
char buffer[40];
- /* An incomplete array is treated like a pointer. */
if (an_int_cst == NULL)
{
- encode_pointer (type, curtype, format);
- return;
- }
+ /* We are trying to encode an incomplete array. An incomplete
+ array is forbidden as part of an instance variable. */
+ if (generating_instance_variables)
+ {
+ /* TODO: Detect this error earlier. */
+ error ("instance variable has unknown size");
+ return;
+ }
+
+ /* So the only case in which an incomplete array could occur is
+ if we are encoding the arguments or return value of a method.
+ In that case, an incomplete array argument or return value
+ (eg, -(void)display: (char[])string) is treated like a
+ pointer because that is how the compiler does the function
+ call. A special, more complicated case, is when the
+ incomplete array is the last member of a struct (eg, if we
+ are encoding "struct { unsigned long int a;double b[];}"),
+ which is again part of a method argument/return value. In
+ that case, we really need to communicate to the runtime that
+ there is an incomplete array (not a pointer!) there. So, we
+ detect that special case and encode it as a zero-length
+ array.
+
+ Try to detect that we are part of a struct. We do this by
+ searching for '=' in the type encoding for the current type.
+ NB: This hack assumes that you can't use '=' as part of a C
+ identifier.
+ */
+ char *enc = obstack_base (&util_obstack) + curtype;
+ if (memchr (enc, '=',
+ obstack_object_size (&util_obstack) - curtype) == NULL)
+ {
+ /* We are not inside a struct. Encode the array as a
+ pointer. */
+ encode_pointer (type, curtype, format);
+ return;
+ }
- if (TREE_INT_CST_LOW (TYPE_SIZE (array_of)) == 0)
+ /* Else, we are in a struct, and we encode it as a zero-length
+ array. */
+ sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0);
+ }
+ else if (TREE_INT_CST_LOW (TYPE_SIZE (array_of)) == 0)
sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)0);
else
sprintf (buffer, "[" HOST_WIDE_INT_PRINT_DEC,
@@ -8055,6 +8162,37 @@ encode_array (tree type, int curtype, int format)
obstack_1grow (&util_obstack, ']');
return;
}
+
+/* Encode a vector. The vector type is a GCC extension to C. */
+static void
+encode_vector (tree type, int curtype, int format)
+{
+ tree vector_of = TREE_TYPE (type);
+ char buffer[40];
+
+ /* Vectors are like simple fixed-size arrays. */
+
+ /* Output ![xx,yy,<code>] where xx is the vector_size, yy is the
+ alignment of the vector, and <code> is the base type. Eg, int
+ __attribute__ ((vector_size (16))) gets encoded as ![16,32,i]
+ assuming that the alignment is 32 bytes. We include size and
+ alignment in bytes so that the runtime does not have to have any
+ knowledge of the actual types.
+ */
+ sprintf (buffer, "![" HOST_WIDE_INT_PRINT_DEC ",%d",
+ /* We want to compute the equivalent of sizeof (<vector>).
+ Code inspired by c_sizeof_or_alignof_type. */
+ ((TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type))
+ / (TYPE_PRECISION (char_type_node) / BITS_PER_UNIT))),
+ /* We want to compute the equivalent of __alignof__
+ (<vector>). Code inspired by
+ c_sizeof_or_alignof_type. */
+ TYPE_ALIGN_UNIT (type));
+ obstack_grow (&util_obstack, buffer, strlen (buffer));
+ encode_type (vector_of, curtype, format);
+ obstack_1grow (&util_obstack, ']');
+ return;
+}
static void
encode_aggregate_fields (tree type, int pointed_to, int curtype, int format)
@@ -8105,12 +8243,64 @@ encode_aggregate_within (tree type, int curtype, int format, int left,
/* NB: aggregates that are pointed to have slightly different encoding
rules in that you never encode the names of instance variables. */
int ob_size = obstack_object_size (&util_obstack);
- char c1 = ob_size > 1 ? *(obstack_next_free (&util_obstack) - 2) : 0;
- char c0 = ob_size > 0 ? *(obstack_next_free (&util_obstack) - 1) : 0;
- int pointed_to = (c0 == '^' || (c1 == '^' && c0 == 'r'));
- int inline_contents
- = ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables)
- && (!pointed_to || ob_size - curtype == (c1 == 'r' ? 2 : 1)));
+ bool inline_contents = false;
+ bool pointed_to = false;
+
+ if (flag_next_runtime)
+ {
+ pointed_to = (ob_size > 0
+ ? *(obstack_next_free (&util_obstack) - 1) == '^'
+ : 0);
+ inline_contents = ((format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables)
+ && (!pointed_to
+ || ob_size - curtype == 1
+ || (ob_size - curtype == 2
+ && *(obstack_next_free (&util_obstack) - 2) == 'r')));
+ }
+ else
+ {
+ /* c0 and c1 are the last two characters in the encoding of the
+ current type; if the last two characters were '^' or '^r',
+ then we are encoding an aggregate that is "pointed to". The
+ comment above applies: in that case we should avoid encoding
+ the names of instance variables.
+ */
+ char c1 = ob_size > 1 ? *(obstack_next_free (&util_obstack) - 2) : 0;
+ char c0 = ob_size > 0 ? *(obstack_next_free (&util_obstack) - 1) : 0;
+
+ if (c0 == '^' || (c1 == '^' && c0 == 'r'))
+ pointed_to = true;
+
+ if (format == OBJC_ENCODE_INLINE_DEFS || generating_instance_variables)
+ {
+ if (!pointed_to)
+ inline_contents = true;
+ else
+ {
+ /* FIXME: It's hard to understand what the following
+ code is meant to be doing. It seems that it will
+ inline contents even if we are encoding a pointed
+ structure and the last characters were 'r^' or just
+ '^'.
+
+ So it seems that in the end the only case where we
+ don't inline contents is '^r', which is a pointer to
+ a 'const' structure! If that is the case, the whole
+ blob of code could be rewritten in a simpler way.
+ */
+ if (c1 == 'r')
+ {
+ if (ob_size - curtype == 2)
+ inline_contents = true;
+ }
+ else
+ {
+ if (ob_size - curtype == 1)
+ inline_contents = true;
+ }
+ }
+ }
+ }
/* Traverse struct aliases; it is important to get the
original struct and its tag name (if any). */
@@ -8150,33 +8340,6 @@ encode_aggregate_within (tree type, int curtype, int format, int left,
obstack_1grow (&util_obstack, right);
}
-static void
-encode_aggregate (tree type, int curtype, int format)
-{
- enum tree_code code = TREE_CODE (type);
-
- switch (code)
- {
- case RECORD_TYPE:
- {
- encode_aggregate_within (type, curtype, format, '{', '}');
- break;
- }
- case UNION_TYPE:
- {
- encode_aggregate_within (type, curtype, format, '(', ')');
- break;
- }
-
- case ENUMERAL_TYPE:
- obstack_1grow (&util_obstack, 'i');
- break;
-
- default:
- break;
- }
-}
-
/* Encode a bitfield NeXT-style (i.e., without a bit offset or the underlying
field type. */
@@ -8188,74 +8351,159 @@ encode_next_bitfield (int width)
obstack_grow (&util_obstack, buffer, strlen (buffer));
}
-/* FORMAT will be OBJC_ENCODE_INLINE_DEFS or OBJC_ENCODE_DONT_INLINE_DEFS. */
+
+/* Encodes 'type', ignoring type qualifiers (which you should encode
+ beforehand if needed) with the exception of 'const', which is
+ encoded by encode_type. See above for the explanation of
+ 'curtype'. 'format' can be OBJC_ENCODE_INLINE_DEFS or
+ OBJC_ENCODE_DONT_INLINE_DEFS.
+*/
static void
encode_type (tree type, int curtype, int format)
{
enum tree_code code = TREE_CODE (type);
char c;
+ /* Ignore type qualifiers other than 'const' when encoding a
+ type. */
+
if (type == error_mark_node)
return;
if (TYPE_READONLY (type))
obstack_1grow (&util_obstack, 'r');
- if (code == INTEGER_TYPE)
+ switch (code)
{
- switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
+ case ENUMERAL_TYPE:
+ if (flag_next_runtime)
{
- case 8: c = TYPE_UNSIGNED (type) ? 'C' : 'c'; break;
- case 16: c = TYPE_UNSIGNED (type) ? 'S' : 's'; break;
- case 32:
- if (type == long_unsigned_type_node
- || type == long_integer_type_node)
- c = TYPE_UNSIGNED (type) ? 'L' : 'l';
- else
- c = TYPE_UNSIGNED (type) ? 'I' : 'i';
+ /* Kludge for backwards-compatibility with gcc-3.3: enums
+ are always encoded as 'i' no matter what type they
+ actually are (!). */
+ c = 'i';
break;
- case 64: c = TYPE_UNSIGNED (type) ? 'Q' : 'q'; break;
- default: abort ();
}
- obstack_1grow (&util_obstack, c);
- }
-
- else if (code == REAL_TYPE)
- {
- /* Floating point types. */
- switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
- {
- case 32: c = 'f'; break;
- case 64:
- case 96:
- case 128: c = 'd'; break;
- default: abort ();
- }
- obstack_1grow (&util_obstack, c);
- }
+ /* Else, they are encoded exactly like the integer type that is
+ used by the compiler to store them. */
+ case INTEGER_TYPE:
+ {
+ switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
+ {
+ case 8: c = TYPE_UNSIGNED (type) ? 'C' : 'c'; break;
+ case 16: c = TYPE_UNSIGNED (type) ? 'S' : 's'; break;
+ case 32:
+ if (flag_next_runtime)
+ {
+ tree int_type;
+ /* Another legacy kludge for compatiblity with
+ gcc-3.3: 32-bit longs are encoded as 'l' or 'L',
+ but not always. For typedefs, we need to use 'i'
+ or 'I' instead if encoding a struct field, or a
+ pointer! */
+ int_type = ((!generating_instance_variables
+ && (obstack_object_size (&util_obstack)
+ == (unsigned) curtype))
+ ? TYPE_MAIN_VARIANT (type)
+ : type);
+
+ if (int_type == long_unsigned_type_node
+ || int_type == long_integer_type_node)
+ c = TYPE_UNSIGNED (type) ? 'L' : 'l';
+ else
+ c = TYPE_UNSIGNED (type) ? 'I' : 'i';
+ }
+ else
+ {
+ if (type == long_unsigned_type_node
+ || type == long_integer_type_node)
+ c = TYPE_UNSIGNED (type) ? 'L' : 'l';
+ else
+ c = TYPE_UNSIGNED (type) ? 'I' : 'i';
+ }
+ break;
+ case 64: c = TYPE_UNSIGNED (type) ? 'Q' : 'q'; break;
+ case 128: c = TYPE_UNSIGNED (type) ? 'T' : 't'; break;
+ default: abort ();
+ }
+ obstack_1grow (&util_obstack, c);
+ break;
+ }
+ case REAL_TYPE:
+ {
+ /* Floating point types. */
+ switch (GET_MODE_BITSIZE (TYPE_MODE (type)))
+ {
+ case 32: c = 'f'; break;
+ case 64: c = 'd'; break;
+ case 96:
+ case 128: c = 'D'; break;
+ default: abort ();
+ }
+ obstack_1grow (&util_obstack, c);
+ break;
+ }
+ case VOID_TYPE:
+ obstack_1grow (&util_obstack, 'v');
+ break;
- else if (code == VOID_TYPE)
- obstack_1grow (&util_obstack, 'v');
+ case BOOLEAN_TYPE:
+ obstack_1grow (&util_obstack, 'B');
+ break;
- else if (code == BOOLEAN_TYPE)
- obstack_1grow (&util_obstack, 'B');
+ case ARRAY_TYPE:
+ encode_array (type, curtype, format);
+ break;
- else if (code == ARRAY_TYPE)
- encode_array (type, curtype, format);
+ case POINTER_TYPE:
+#ifdef OBJCPLUS
+ case REFERENCE_TYPE:
+#endif
+ encode_pointer (type, curtype, format);
+ break;
- else if (code == POINTER_TYPE)
- encode_pointer (type, curtype, format);
+ case RECORD_TYPE:
+ encode_aggregate_within (type, curtype, format, '{', '}');
+ break;
- else if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE)
- encode_aggregate (type, curtype, format);
+ case UNION_TYPE:
+ encode_aggregate_within (type, curtype, format, '(', ')');
+ break;
- else if (code == FUNCTION_TYPE) /* '?' */
- obstack_1grow (&util_obstack, '?');
+ case FUNCTION_TYPE: /* '?' means an unknown type. */
+ obstack_1grow (&util_obstack, '?');
+ break;
- else if (code == COMPLEX_TYPE)
- {
+ case COMPLEX_TYPE:
+ /* A complex is encoded as 'j' followed by the inner type (eg,
+ "_Complex int" is encoded as 'ji'). */
obstack_1grow (&util_obstack, 'j');
encode_type (TREE_TYPE (type), curtype, format);
+ break;
+
+ case VECTOR_TYPE:
+ encode_vector (type, curtype, format);
+ break;
+
+ default:
+ warning (0, "unknown type %s found during Objective-C encoding",
+ gen_type_name (type));
+ obstack_1grow (&util_obstack, '?');
+ break;
+ }
+
+ if (flag_next_runtime)
+ {
+ /* Super-kludge. Some ObjC qualifier and type combinations need
+ to be rearranged for compatibility with gcc-3.3. */
+ if (code == POINTER_TYPE && obstack_object_size (&util_obstack) >= 3)
+ {
+ char *enc = obstack_base (&util_obstack) + curtype;
+
+ /* Rewrite "in const" from "nr" to "rn". */
+ if (curtype >= 1 && !strncmp (enc - 1, "nr", 2))
+ strncpy (enc - 1, "rn", 2);
+ }
}
}
@@ -8266,12 +8514,14 @@ encode_gnu_bitfield (int position, tree type, int size)
char buffer[40];
char charType = '?';
- if (code == INTEGER_TYPE)
+ /* This code is only executed for the GNU runtime, so we can ignore
+ the NeXT runtime kludge of always encoding enums as 'i' no matter
+ what integers they actually are. */
+ if (code == INTEGER_TYPE || code == ENUMERAL_TYPE)
{
if (integer_zerop (TYPE_MIN_VALUE (type)))
+ /* Unsigned integer types. */
{
- /* Unsigned integer types. */
-
if (TYPE_MODE (type) == QImode)
charType = 'C';
else if (TYPE_MODE (type) == HImode)
@@ -8286,7 +8536,6 @@ encode_gnu_bitfield (int position, tree type, int size)
else if (TYPE_MODE (type) == DImode)
charType = 'Q';
}
-
else
/* Signed integer types. */
{
@@ -8306,10 +8555,12 @@ encode_gnu_bitfield (int position, tree type, int size)
charType = 'q';
}
}
- else if (code == ENUMERAL_TYPE)
- charType = 'i';
else
- abort ();
+ {
+ /* Do not do any encoding, produce an error and keep going. */
+ error ("trying to encode non-integer type as a bitfield");
+ return;
+ }
sprintf (buffer, "b%d%c%d", position, charType, size);
obstack_grow (&util_obstack, buffer, strlen (buffer));
@@ -8335,7 +8586,7 @@ encode_field_decl (tree field_decl, int curtype, int format)
encode_next_bitfield (size);
else
encode_gnu_bitfield (int_bit_position (field_decl),
- DECL_BIT_FIELD_TYPE (field_decl), size);
+ DECL_BIT_FIELD_TYPE (field_decl), size);
}
else
encode_type (TREE_TYPE (field_decl), curtype, format);