diff options
-rw-r--r-- | gcc/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/doc/objc.texi | 182 | ||||
-rw-r--r-- | gcc/objc/ChangeLog | 48 | ||||
-rw-r--r-- | gcc/objc/objc-act.c | 447 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 60 | ||||
-rw-r--r-- | gcc/testsuite/obj-c++.dg/encode-1-next.mm | 26 | ||||
-rw-r--r-- | gcc/testsuite/obj-c++.dg/encode-1.mm | 1 | ||||
-rw-r--r-- | gcc/testsuite/obj-c++.dg/encode-5.mm | 16 | ||||
-rw-r--r-- | gcc/testsuite/obj-c++.dg/threedotthree-abi-1.mm | 71 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/encode-1.m | 1 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/encode-3.m | 18 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/encode-6-next.m | 23 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/encode-6.m | 1 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/encode-7-next-64bit.m | 266 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/encode-7-next.m | 267 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/proto-qual-1.m | 10 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/threedotthree-abi-1.m | 68 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/type-size-2.m | 15 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/type-size-3.m | 18 | ||||
-rw-r--r-- | libobjc/ChangeLog | 10 | ||||
-rw-r--r-- | libobjc/encoding.c | 79 | ||||
-rw-r--r-- | libobjc/objc/encoding.h | 2 | ||||
-rw-r--r-- | libobjc/objc/objc-api.h | 12 |
23 files changed, 1537 insertions, 121 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7954df7..68dd7e9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,22 @@ 2010-09-27 Nicola Pero <nicola.pero@meta-innovation.com> + * doc/objc.texi (Type encoding): Added the new 'long double' (D) + code. Added byref, which was missing in the list of codes. + Explain that enumeration values are encoded as the integer type + that the compiler uses to store them. Explain and make examples + of how 'const' interacts with pointers, and the complication of + the encoding of 'const char *'. + (Legacy type encoding): New subsection, explaining that GCC emits + incorrect type encodings for the NeXT runtime for compatibility + reasons. + (@@encode): New subsection, explaining @encode and particularly + that protocol qualifiers are not recognized inside an @encode() + expression. + (Method signatures): New subsection, explaining how method + signatures are encoded. + +2010-09-27 Nicola Pero <nicola.pero@meta-innovation.com> + Merge from 'apple/trunk' branch on FSF servers. Removed small change in build_conditional_expr that had been added when fixing PR objc/27377 and which did the same check in a less complete way. diff --git a/gcc/doc/objc.texi b/gcc/doc/objc.texi index 1beb748..bf32879 100644 --- a/gcc/doc/objc.texi +++ b/gcc/doc/objc.texi @@ -170,9 +170,13 @@ above apply to classes defined in bundle. @node Type encoding @section Type encoding -The Objective-C compiler generates type encodings for all the -types. These type encodings are used at runtime to find out information -about selectors and methods and about objects and classes. +This is an advanced section. Type encodings are used extensively by +the compiler and by the runtime, but you generally do not need to know +about them to use Objective-C. + +The Objective-C compiler generates type encodings for all the types. +These type encodings are used at runtime to find out information about +selectors and methods and about objects and classes. The types are encoded in the following way: @@ -205,6 +209,8 @@ The types are encoded in the following way: @tab @code{f} @item @code{double} @tab @code{d} +@item @code{long double} +@tab @code{D} @item @code{void} @tab @code{v} @item @code{id} @@ -215,6 +221,9 @@ The types are encoded in the following way: @tab @code{:} @item @code{char*} @tab @code{*} +@item @code{enum} +@tab an @code{enum} is encoded exactly as the integer type that the compiler uses for it, which depends on the enumeration +values. Often the compiler users @code{unsigned int}, which is then encoded as @code{I}. @item unknown type @tab @code{?} @item Complex types @@ -225,15 +234,16 @@ The types are encoded in the following way: @c @sp 1 -The encoding of bit-fields has changed to allow bit-fields to be properly -handled by the runtime functions that compute sizes and alignments of -types that contain bit-fields. The previous encoding contained only the -size of the bit-field. Using only this information it is not possible to -reliably compute the size occupied by the bit-field. This is very -important in the presence of the Boehm's garbage collector because the -objects are allocated using the typed memory facility available in this -collector. The typed memory allocation requires information about where -the pointers are located inside the object. +The encoding of bit-fields has changed to allow bit-fields to be +properly handled by the runtime functions that compute sizes and +alignments of types that contain bit-fields. The previous encoding +contained only the size of the bit-field. Using only this information +it is not possible to reliably compute the size occupied by the +bit-field. This is very important in the presence of the Boehm's +garbage collector because the objects are allocated using the typed +memory facility available in this collector. The typed memory +allocation requires information about where the pointers are located +inside the object. The position in the bit-field is the position, counting in bits, of the bit closest to the beginning of the structure. @@ -251,6 +261,8 @@ The non-atomic types are encoded as follows: @tab @samp{@{} followed by the name of the structure (or @samp{?} if the structure is unnamed), the @samp{=} sign, the type of the members and by @samp{@}} @item unions @tab @samp{(} followed by the name of the structure (or @samp{?} if the union is unnamed), the @samp{=} sign, the type of the members followed by @samp{)} +@item vectors +@tab @samp{![} followed by the vector_size (the number of bytes composing the vector) followed by a comma, followed by the alignment (in bytes) of the vector, followed by the type of the elements followed by @samp{]} @end multitable Here are some types and their encodings, as they are generated by the @@ -277,6 +289,11 @@ struct @{ @} @end smallexample @tab @code{@{?=i[3f]b128i3b131i2c@}} +@item +@smallexample +int a __attribute__ ((vector_size (16))); +@end smallexample +@tab @code{![16,16i]} (alignment would depend on the machine) @end multitable @sp 1 @@ -300,6 +317,8 @@ Objective-C type specifiers: @tab @code{o} @item @code{bycopy} @tab @code{O} +@item @code{byref} +@tab @code{R} @item @code{oneway} @tab @code{V} @end multitable @@ -310,6 +329,145 @@ The type specifiers are encoded just before the type. Unlike types however, the type specifiers are only encoded when they appear in method argument types. +Note how @code{const} interacts with pointers: + +@sp 1 + +@multitable @columnfractions .25 .75 +@item Objective-C type +@tab Compiler encoding +@item +@smallexample +const int +@end smallexample +@tab @code{ri} +@item +@smallexample +const int* +@end smallexample +@tab @code{^ri} +@item +@smallexample +int *const +@end smallexample +@tab @code{r^i} +@end multitable + +@sp 1 + +@code{const int*} is a pointer to a @code{const int}, and so is +encoded as @code{^ri}. @code{int* const}, instead, is a @code{const} +pointer to an @code{int}, and so is encoded as @code{r^i}. + +Finally, there is a complication when encoding @code{const char *} +versus @code{char * const}. Because @code{char *} is encoded as +@code{*} and not as @code{^c}, there is no way to express the fact +that @code{r} applies to the pointer or to the pointee. + +Hence, it is assumed as a convention that @code{r*} means @code{const +char *} (since it is what is most often meant), and there is no way to +encode @code{char *const}. @code{char *const} would simply be encoded +as @code{*}, and the @code{const} is lost. + +@menu +* Legacy type encoding:: +* @@encode:: +* Method signatures:: +@end menu + +@node Legacy type encoding +@subsection Legacy type encoding + +Unfortunately, historically GCC used to have a number of bugs in its +encoding code. The NeXT runtime expects GCC to emit type encodings in +this historical format (compatible with GCC-3.3), so when using the +NeXT runtime, GCC will introduce on purpose a number of incorrect +encodings: + +@itemize @bullet + +@item +the read-only qualifier of the pointee gets emitted before the '^'. +The read-only qualifier of the pointer itself gets ignored, unless it +is a typedef. Also, the 'r' is only emitted for the outermost type. + +@item +32-bit longs are encoded as 'l' or 'L', but not always. For typedefs, +the compiler uses 'i' or 'I' instead if encoding a struct field or a +pointer. + +@item +@code{enum}s are always encoded as 'i' (int) even if they are actually +unsigned or long. + +@end itemize + +In addition to that, the NeXT runtime uses a different encoding for +bitfields. It encodes them as @code{b} followed by the size, without +a bit offset or the underlying field type. + +@node @@encode +@subsection @@encode + +GNU Objective-C supports the @code{@@encode} syntax that allows you to +create a type encoding from a C/Objective-C type. For example, +@code{@@encode(int)} is compiled by the compiler into @code{"i"}. + +@code{@@encode} does not support type qualifiers other than +@code{const}. For example, @code{@@encode(const char*)} is valid and +is compiled into @code{"r*"}, while @code{@@encode(bycopy char *)} is +invalid and will cause a compilation error. + +@node Method signatures +@subsection Method signatures + +This section documents the encoding of method types, which is rarely +needed to use Objective-C. You should skip it at a first reading; the +runtime provides functions that will work on methods and can walk +through the list of parameters and interpret them for you. These +functions are part of the public ``API'' and are the preferred way to +interact with method signatures from user code. + +But if you need to debug a problem with method signatures and need to +know how they are implemented (ie, the ``ABI''), read on. + +Methods have their ``signature'' encoded and made available to the +runtime. The ``signature'' encodes all the information required to +dynamically build invocations of the method at runtime: return type +and arguments. + +The ``signature'' is a null-terminated string, composed of the following: + +@itemize @bullet + +@item +The return type, including type qualifiers. For example, a method +returning @code{int} would have @code{i} here. + +@item +The total size (in bytes) required to pass all the parameters. This +includes the two hidden parameters (the object @code{self} and the +method selector @code{_cmd}). + +@item +Each argument, with the type encoding, followed by the offset (in +bytes) of the argument in the list of parameters. + +@end itemize + +For example, a method with no arguments and returning @code{int} would +have the signature @code{i8@@0:4} if the size of a pointer is 4. The +signature is interpreted as follows: the @code{i} is the return type +(an @code{int}), the @code{8} is the total size of the parameters in +bytes (two pointers each of size 4), the @code{@@0} is the first +parameter (an object at byte offset @code{0}) and @code{:4} is the +second parameter (a @code{SEL} at byte offset @code{4}). + +You can easily find more examples by running the ``strings'' program +on an Objective-C object file compiled by GCC. You'll see a lot of +strings that look very much like @code{i8@@0:4}. They are signatures +of Objective-C methods. + @node Garbage Collection @section Garbage Collection diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 8e70e20..b1fb7bc 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,5 +1,53 @@ 2010-09-27 Nicola Pero <nicola.pero@meta-innovation.com> + PR objc/45763 + PR objc/25450 + PR objc/25464 + * objc-act.c: Improved comments for encoding functions. + (encode_aggregate_within): For the GNU runtime, rewritten some + obsfuscated code to clarify the various cases. + (encode_aggregate): Function removed. + (encode_array): Generate an error if asked to encode an incomplete + array as part of generating instance variables. Else, when + encoding an incomplete array inside a structure, encode it as an + array of zero size. + (encode_pointer): For the GNU runtime, fixed encoding 'BOOL *' as + '^c' instead of '*'. + (encode_gnu_bitfield): Encode enumerated types exactly in the same + type as integer types instead of using a hardcoded 'i'. If asked + to encode a non-integer type as a bitfield, do not abort + compilation immediately; instead generate an error, then skip the + type. + (encode_type): Use a 'switch' instead of a sequence of 'if's. + Added a 'default' clause that gets executed if the type can not be + matched, and that encodes it as '?' (unknown) and produces a + warning. For the GNU runtime, encode enumerated types exactly in + the same way as integer types instead of using a hardcoded 'i'. + Encode long double as 'D'. Encode 128-bit integers as 'T' or 't'. + Encode C++ reference types as pointers. Call encode_vector to + encode vectors. + (encode_vector): New function. + +2010-09-27 Nicola Pero <nicola.pero@meta-innovation.com> + + Merge from 'apple/trunk' branch on FSF servers. I modified the + changes to be used only when compiling for the NeXT runtime. + + 2005-10-10 Fariborz Jahanian <fjahanian@apple.com> + + Radar 4301047 + + * objc-act.c (encode_type): Remove the hack. + + 2005-07-20 Ziemowit Laski <zlaski@apple.com> + + Radar 4136935 + * objc-act.c (pointee_is_readonly): New function. + (encode_pointer, encode_aggregate_within, encode_type): + Attempt to emulate GCC 3.3 when generating type encodings. + +2010-09-27 Nicola Pero <nicola.pero@meta-innovation.com> + Merge from 'apple/trunk' branch on FSF servers. 2005-12-15 Fariborz Jahanian <fjahanian@apple.com> diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 5d76596..101f9fc 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); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 24f0c17..150dac4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,65 @@ 2010-09-27 Nicola Pero <nicola.pero@meta-innovation.com> + PR objc/25464 + * objc.dg/type-size-3.m: New test. + +2010-09-27 Nicola Pero <nicola.pero@meta-innovation.com> + + PR objc/45763 + * objc.dg/encode-1.m: Execute the test with the GNU runtime as + well. + +2010-09-27 Nicola Pero <nicola.pero@meta-innovation.com> + + PR objc/25450 + * objc.dg/encode-3.m: Updated for fix of encoding of enums. + * objc.dg/type-size-2.m: Same change. + * obj-c++.dg/encode-5.mm: Same change. + +2010-09-27 Nicola Pero <nicola.pero@meta-innovation.com> + + Merge from 'apple/trunk' branch on FSF servers. The original + Changelogs are below. + + * objc.dg/encode-6.m: Execute the test only with the GNU runtime. + * objc.dg/encode-6-next.m: New file (from encode-6.m in the + branch). + * objc.dg/encode-7-next.m: New file (from encode-7.m in the + branch). + * objc.dg/encode-7-next-64bit.m: New file (from encode-7-64bit.m + in the branch). + * objc.dg/proto-qual-1.m: Test the 3.3 ABI on NeXT (from + proto-qual-1.m in the branch) and the normal ABI on GNU. + * objc.dg/threedotthree-abi-1.m: New file (from the branch). Run + the test only with the NeXT runtime. + * obj-c++/encode-1.mm: Execute the test only with the GNU runtime. + * obj-c++/encode-1-next.mm: New file (from encode-1.mm in the + branch). + * obj-c++.dg/threedotthree-abi-1.mm: New file (from the branch). + Run the test only with the NeXT runtime. + + 2006-03-30 Fariborz Jahanian <fjahanian@apple.com> + + Radar 4492973 + * objc.dg/encode-7-64bit.m: New. + * objc.dg/encode-7.m: Skip if -m64. + + 2005-10-19 Fariborz Jahanian <fjahanian@apple.com> + + Radar 4301047 + * objc.dg/proto-qual-1.m: Fix test to match 3.3 ABI + * obj-c++.dg/threedotthree-abi-1.mm: New + * objc.dg/threedotthree-abi-1.m: New + + 2005-07-20 Ziemowit Laski <zlaski@apple.com> + + Radar 4136935 + * obj-c++.dg/encode-1.mm: Tweak encodings to match fix. + * objc.dg/encode-6.m: Likewise. + * objc.dg/encode-7.m: New test case. + +2010-09-27 Nicola Pero <nicola.pero@meta-innovation.com> + Merge from 'apple/trunk' branch on FSF servers. Renamed const-str-12.m to constr-str-12b.m to avoid conflicts. diff --git a/gcc/testsuite/obj-c++.dg/encode-1-next.mm b/gcc/testsuite/obj-c++.dg/encode-1-next.mm new file mode 100644 index 0000000..47673f2 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/encode-1-next.mm @@ -0,0 +1,26 @@ +/* This file tests that things are encoded using the gcc-3.3 ABI which is only + used by the NeXT runtime. */ +/* Test for graceful encoding of const-qualified fields and parameters. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ + +struct Cxx { + const struct Cxx *next; +}; + +@interface ObjC { + const struct Cxx *obj; +} +- (ObjC *)initWithCxx: (struct Cxx *const)c and: (const struct Cxx *)d; +@end + +@implementation ObjC +- (ObjC *)initWithCxx: (struct Cxx *const)c and: (const struct Cxx *)d { + obj = d; + return self; +} +@end + +/* { dg-final { scan-assembler "@\[0-9\]+@0:\[0-9\]+\\^{Cxx=\\^{Cxx}}\[0-9\]+r\\^{Cxx=\\^{Cxx}}" } } */ diff --git a/gcc/testsuite/obj-c++.dg/encode-1.mm b/gcc/testsuite/obj-c++.dg/encode-1.mm index c5f5ea9..5f5ba20 100644 --- a/gcc/testsuite/obj-c++.dg/encode-1.mm +++ b/gcc/testsuite/obj-c++.dg/encode-1.mm @@ -2,6 +2,7 @@ /* Author: Ziemowit Laski <zlaski@apple.com> */ /* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ struct Cxx { const struct Cxx *next; diff --git a/gcc/testsuite/obj-c++.dg/encode-5.mm b/gcc/testsuite/obj-c++.dg/encode-5.mm index 4959ea3..18db3f3 100644 --- a/gcc/testsuite/obj-c++.dg/encode-5.mm +++ b/gcc/testsuite/obj-c++.dg/encode-5.mm @@ -70,7 +70,21 @@ int main(void) { CHECK_IF(offs3 == offs2 + sizeof(XXRect) && offs4 == offs3 + sizeof(int)); CHECK_IF(totsize == offs4 + sizeof(int)); meth = [proto descriptionForClassMethod: @selector(getEnum:enum:bool:)]; - scan_initial("^i%u@%u:%u^{?=ff(__XXAngle=II)}%ui%uc%u"); + /* Here we have the complication that 'enum Enum' could be encoded + as 'i' on __NEXT_RUNTIME_, and (most likely) as 'I' on the GNU + runtime. So we get the @encode(enum Enum), then put it into the + string in place of the traditional 'i'. + */ + /* scan_initial("^i%u@%u:%u^{?=ff(__XXAngle=II)}%ui%uc%u"); */ + { + char pattern[1024]; + + sprintf (pattern, "^%s%%u@%%u:%%u^{?=ff(__XXAngle=II)}%%u%s%%uc%%u", + @encode(enum Enum), @encode(enum Enum)); + scan_initial(pattern); + } + + CHECK_IF(offs3 == offs2 + sizeof(XXPoint *) && offs4 == offs3 + sizeof(enum Enum)); CHECK_IF(totsize == offs4 + sizeof(int)); /* 'ObjCBool' is really 'char' */ meth = [proto descriptionForClassMethod: @selector(getBool:)]; diff --git a/gcc/testsuite/obj-c++.dg/threedotthree-abi-1.mm b/gcc/testsuite/obj-c++.dg/threedotthree-abi-1.mm new file mode 100644 index 0000000..56fa701 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/threedotthree-abi-1.mm @@ -0,0 +1,71 @@ +/* This file tests that things are encoded using the gcc-3.3 ABI which is only + used by the NeXT runtime. */ +/* { dg-do run { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +#include <stdio.h> +#include <string.h> +#include "../objc-obj-c++-shared/Protocol1.h" +#ifndef __NEXT_RUNTIME__ +#include <objc/objc-api.h> +#endif + +extern "C" void abort(); + + +@protocol CommonProtocol + +-(oneway void)methodCall_On:(in bycopy id)someValue_On; +-(oneway void)methodCall_nO:(bycopy in id)someValue_nO; + +-(oneway void)methodCall_Oo:(out bycopy id)someValue_Oo; +-(oneway void)methodCall_oO:(bycopy out id)someValue_oO; + +-(oneway void)methodCall_rn:(in const id)someValue_rn; + +-(oneway void)methodCall_oOn:(in bycopy out id)someValue_oOn; + +@end + +@interface ObjCClass <CommonProtocol> +{ + +} + +@end + +@implementation ObjCClass +-(oneway void)methodCall_On:(in bycopy id)someValue_On { } +-(oneway void)methodCall_nO:(bycopy in id)someValue_nO { } + +-(oneway void)methodCall_Oo:(out bycopy id)someValue_Oo { } +-(oneway void)methodCall_oO:(bycopy out id)someValue_oO { } + +-(oneway void)methodCall_rn:(in const id)someValue_rn { } +-(oneway void)methodCall_oOn:(in bycopy out id)someValue_oOn { } +@end + +Protocol *proto = @protocol(CommonProtocol); +struct objc_method_description *meth; + +int main() +{ + meth = [proto descriptionForInstanceMethod: @selector(methodCall_On:)]; + if (strcmp (meth->types, "Vv12@0:4On@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_nO:)]; + if (strcmp (meth->types, "Vv12@0:4nO@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_Oo:)]; + if (strcmp (meth->types, "Vv12@0:4Oo@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_oO:)]; + if (strcmp (meth->types, "Vv12@0:4oO@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_rn:)]; + if (strcmp (meth->types, "Vv12@0:4rn@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_oOn:)]; + if (strcmp (meth->types, "Vv12@0:4oOn@8")) + abort(); + return 0; +} diff --git a/gcc/testsuite/objc.dg/encode-1.m b/gcc/testsuite/objc.dg/encode-1.m index 50e9919..09cb6af 100644 --- a/gcc/testsuite/objc.dg/encode-1.m +++ b/gcc/testsuite/objc.dg/encode-1.m @@ -4,7 +4,6 @@ where we have 'typedef char BOOL'. */ /* Contributed by Ziemowit Laski <zlaski@apple.com>. */ /* { dg-do run } */ -/* { dg-options "-fnext-runtime" } */ #include <string.h> #include <stdlib.h> #include <objc/objc.h> diff --git a/gcc/testsuite/objc.dg/encode-3.m b/gcc/testsuite/objc.dg/encode-3.m index 63a92e1..4322453 100644 --- a/gcc/testsuite/objc.dg/encode-3.m +++ b/gcc/testsuite/objc.dg/encode-3.m @@ -44,7 +44,7 @@ unsigned totsize, offs0, offs1, offs2, offs3, offs4, offs5, offs6, offs7; static void scan_initial(const char *pattern) { totsize = offs0 = offs1 = offs2 = offs3 = offs4 = offs5 = offs6 = offs7 = (unsigned)-1; sscanf(meth->types, pattern, &totsize, &offs0, &offs1, &offs2, &offs3, - &offs4, &offs5, &offs6, &offs7); + &offs4, &offs5, &offs6, &offs7); CHECK_IF(!offs0 && offs1 == sizeof(id) && offs2 == offs1 + sizeof(SEL) && totsize >= offs2); } @@ -65,7 +65,21 @@ int main(void) { CHECK_IF(offs3 == offs2 + sizeof(XXRect) && offs4 == offs3 + sizeof(int)); CHECK_IF(totsize == offs4 + sizeof(int)); meth = [proto descriptionForClassMethod: @selector(getEnum:enum:bool:)]; - scan_initial("^i%u@%u:%u^{?=ff(__XXAngle=II)}%ui%uc%u"); + + /* Here we have the complication that 'enum Enum' could be encoded + as 'i' on __NEXT_RUNTIME_, and (most likely) as 'I' on the GNU + runtime. So we get the @encode(enum Enum), then put it into the + string in place of the traditional 'i'. + */ + /* scan_initial("^i%u@%u:%u^{?=ff(__XXAngle=II)}%ui%uc%u"); */ + { + char pattern[1024]; + + sprintf (pattern, "^%s%%u@%%u:%%u^{?=ff(__XXAngle=II)}%%u%s%%uc%%u", + @encode(enum Enum), @encode(enum Enum)); + scan_initial(pattern); + } + CHECK_IF(offs3 == offs2 + sizeof(XXPoint *) && offs4 == offs3 + sizeof(enum Enum)); CHECK_IF(totsize == offs4 + sizeof(int)); /* 'ObjCBool' is really 'char' */ meth = [proto descriptionForClassMethod: @selector(getBool:)]; diff --git a/gcc/testsuite/objc.dg/encode-6-next.m b/gcc/testsuite/objc.dg/encode-6-next.m new file mode 100644 index 0000000..c3d9226 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-6-next.m @@ -0,0 +1,23 @@ +/* Test for graceful encoding of const-qualified fields and parameters. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ + +struct Cxx { + const struct Cxx *next; +}; + +@interface ObjC { + const struct Cxx *obj; +} +- (ObjC *)initWithCxx: (struct Cxx *const)c and: (const struct Cxx *)d; +@end + +@implementation ObjC +- (ObjC *)initWithCxx: (struct Cxx *const)c and: (const struct Cxx *)d { + obj = d; + return self; +} +@end + +/* { dg-final { scan-assembler "@\[0-9\]+@0:\[0-9\]+\\^{Cxx=\\^{Cxx}}\[0-9\]+r\\^{Cxx=\\^{Cxx}}" } } */ diff --git a/gcc/testsuite/objc.dg/encode-6.m b/gcc/testsuite/objc.dg/encode-6.m index 263b02a..291a41e 100644 --- a/gcc/testsuite/objc.dg/encode-6.m +++ b/gcc/testsuite/objc.dg/encode-6.m @@ -1,6 +1,7 @@ /* Test for graceful encoding of const-qualified fields and parameters. */ /* Author: Ziemowit Laski <zlaski@apple.com> */ /* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */ struct Cxx { const struct Cxx *next; diff --git a/gcc/testsuite/objc.dg/encode-7-next-64bit.m b/gcc/testsuite/objc.dg/encode-7-next-64bit.m new file mode 100644 index 0000000..2a064d8 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-7-next-64bit.m @@ -0,0 +1,266 @@ +/* Additional testing for the NeXT runtime. Encoding in -m64 mode */ + +/* { dg-do run { target *-*-darwin* } } */ +/* { dg-options "-m64" } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ + +#include <objc/Object.h> +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#define CHECK_IF(E) if (!(E)) abort () + +@class NSDictionary, NSFont, NSError, _NSATSTypesetterGuts, NSString, NSMenu, NSArray; + +typedef unsigned char UInt8; +typedef const signed long OSStatus; +typedef unsigned long CFIndex; +typedef unsigned int UInt32; +typedef UInt32 FourCharCode; +typedef FourCharCode OSType; + +struct FSRef { + UInt8 hidden[80]; +}; +typedef struct FSRef FSRef; + +typedef struct _NSPoint { + float x; + float y; +} NSPoint; + +typedef struct _NSSize { + float width; + float height; +} NSSize; + +typedef struct _NSRect { + NSPoint origin; + NSSize size; +} NSRect; + +typedef struct _NSRange { + unsigned int location; + unsigned int length; +} NSRange; + +typedef const char *NXAtom; + +typedef struct { + NSDictionary *_attributes; + NSFont *_font; + CFIndex _characterLength; + CFIndex _nominalGlyphLocation; + const CFIndex *p; + float _defaultLineHeight; + float _defaultBaselineOffset; + float _horizExpansion; + float _baselineDelta; + NSRect _attachmentBBox; + long ll, *llp; + unsigned long ull, *ullp; + id a; + const id a1; + const struct objc_object *a2; + SEL b; + const SEL b1; + const struct objc_selector *b2; + const char *str1; + char *str2; + char *const str3; + const char *const str4; + struct { + unsigned int _isAttachmentRun:1; + unsigned int _hasPositionalStake:1; + unsigned int _isDefaultFace:1; + unsigned int _hasCombiningMarks:1; + unsigned int _isScreenFont:1; + unsigned int _reserved:27; + } _rFlags; +} NSATSGlyphStorageRun; + +typedef struct __CFSet *CFMutableSetRef; +typedef const struct __CTLine * CTLineRef; +typedef const struct __NSAppleEventManagerSuspension* NSAppleEventManagerSuspensionID; + +struct ComponentInstanceRecord { + long data[1]; +}; +typedef struct ComponentInstanceRecord ComponentInstanceRecord; +typedef ComponentInstanceRecord *ComponentInstance; + +typedef NSString *(*NSErrorUserInfoFormatterFunc)(id objToBeDisplayed, NSError *err, char modifier); +typedef struct { + NSErrorUserInfoFormatterFunc formatterFunc; + NSString *userInfoKey; + unsigned int parameterMask; +} NSErrorUserInfoFormatter; + +typedef Object MyObj; +typedef Object *MyPtr; + +@interface Foo: Object { + NSATSGlyphStorageRun r; +} +- (NSError *)_errorWithOSStatus:(OSStatus)inOSStatus ref1:(const FSRef *)inRef1 ref2:(const struct FSRef *)inRef2 + reading:(BOOL)inReadingNotWriting; +- (const NSATSGlyphStorageRun *)_attributeRunForCharacterAtIndex:(const CFIndex)charIndex; +- (const _NSATSTypesetterGuts *)_getATSTypesetterGuts:(const struct objc_selector *)sel; +- (void)resumeWithSuspensionID:(NSAppleEventManagerSuspensionID)suspensionID and:(const CFIndex *)status; +- (const id)anotherMeth:(const SEL)sel and:(const Foo *)foo and:(const struct objc_object *)obj; +- (id)str1:(const char *)str1 str2:(char *)str2 str3:(char *const)str3 str4:(const char *const)str4; +- (oneway void)foo1:(Foo *)foo1 foo2:(const Foo *)foo2 foo3:(Foo *const)foo3 foo4:(const Foo *const)foo4; +- (in const char *)sel1:(const SEL)sel1 id1:(const id)id1; +- (inout id)obj1:(const MyPtr)obj1 obj2:(Object *const)obj2 obj3:(MyObj *const)obj3; ++ (ComponentInstance)_defaultScriptingComponent; +- (NSString *)_formatCocoaErrorString:(NSString *)formatString parameters:(const char *)parameters + applicableFormatters:(NSErrorUserInfoFormatter **)formatters count:(int)numFormatters; +- (NSErrorUserInfoFormatter *)formatter_func:(id)obj run:(const NSATSGlyphStorageRun **)run; +- (BOOL)_forgetWord:(bycopy in NSString *)word inDictionary:(bycopy in NSString *)language; +- (void)_registerServicesMenu:(NSMenu *)servicesMenu withSendTypes:(const NXAtom *)sendTypes + andReturnTypes:(const NXAtom *)returnTypes addToList:(BOOL)addToList; ++ (CFMutableSetRef *)_proxySharePointer; +- (NSRange)_checkGrammarInString:(in NSString *)stringToCheck language:(bycopy in NSString *)language details:(bycopy out NSArray **)details; +- (bool)_resolvePositionalStakeGlyphsForLineFragment:(CTLineRef)line lineFragmentRect:(NSRect)lineFragmentRect + minPosition:(float)minPosition maxPosition:(float)maxPosition maxLineFragmentWidth:(float)maxLineFragmentWidth + breakHint:(CFIndex *)charIndex; ++ (BOOL)findVoiceByIdentifier:(NSString *)identifier returningCreator:(OSType *)returnedCreator returningID:(OSType *)returnedID; +@end + +NSRange globalRange; + +@implementation Foo +- (NSError *)_errorWithOSStatus:(OSStatus)inOSStatus ref1:(const FSRef *)inRef1 ref2:(const struct FSRef *)inRef2 + reading:(BOOL)inReadingNotWriting { + return (NSError *)self; +} +- (const NSATSGlyphStorageRun *)_attributeRunForCharacterAtIndex:(CFIndex)charIndex { + return (const NSATSGlyphStorageRun *)self; +} +- (const _NSATSTypesetterGuts *)_getATSTypesetterGuts:(const struct objc_selector *)sel { + return (const _NSATSTypesetterGuts *)self; +} +- (void)resumeWithSuspensionID:(NSAppleEventManagerSuspensionID)suspensionID and:(const CFIndex *)status { +} +- (const id)anotherMeth:(const SEL)sel and:(const Foo *)foo and:(const struct objc_object *)obj { + return (const id)self; +} +- (id)str1:(const char *)str1 str2:(char *)str2 str3:(char *const)str3 str4:(const char *const)str4 { + return self; +} +- (oneway void)foo1:(Foo *)foo1 foo2:(const Foo *)foo2 foo3:(Foo *const)foo3 foo4:(const Foo *const)foo4 { +} +- (in const char *)sel1:(const SEL)sel1 id1:(const id)id1 { + return "Hello"; +} +- (inout id)obj1:(const MyPtr)obj1 obj2:(Object *const)obj2 obj3:(MyObj *const)obj3 { + return self; +} ++ (ComponentInstance)_defaultScriptingComponent { + return (ComponentInstance)0; +} +- (NSString *)_formatCocoaErrorString:(NSString *)formatString parameters:(const char *)parameters + applicableFormatters:(NSErrorUserInfoFormatter **)formatters count:(int)numFormatters { + return (NSString *)self; +} +- (NSErrorUserInfoFormatter *)formatter_func:(id)obj run:(const NSATSGlyphStorageRun **)run { + return (NSErrorUserInfoFormatter *)0; +} +- (BOOL)_forgetWord:(bycopy in NSString *)word inDictionary:(bycopy in NSString *)language { + return YES; +} +- (void)_registerServicesMenu:(NSMenu *)servicesMenu withSendTypes:(const NXAtom *)sendTypes + andReturnTypes:(const NXAtom *)returnTypes addToList:(BOOL)addToList { +} ++ (CFMutableSetRef *)_proxySharePointer { + return (CFMutableSetRef *)0; +} +- (NSRange)_checkGrammarInString:(in NSString *)stringToCheck language:(bycopy in NSString *)language details:(bycopy out NSArray **)details { + return globalRange; +} +- (bool)_resolvePositionalStakeGlyphsForLineFragment:(CTLineRef)line lineFragmentRect:(NSRect)lineFragmentRect + minPosition:(float)minPosition maxPosition:(float)maxPosition maxLineFragmentWidth:(float)maxLineFragmentWidth + breakHint:(CFIndex *)charIndex { + return false; +} ++ (BOOL)findVoiceByIdentifier:(NSString *)identifier returningCreator:(OSType *)returnedCreator returningID:(OSType *)returnedID { + return NO; +} +@end + +int main(void) { + Class fooClass = objc_getClass ("Foo"); + Method meth; + struct objc_ivar_list *ivars; + struct objc_ivar *ivar; + + meth = class_getInstanceMethod (fooClass, @selector(_errorWithOSStatus:ref1:ref2:reading:)); + CHECK_IF (!strcmp (meth->method_types, "@44@0:8q16r^{FSRef=[80C]}24r^{FSRef=[80C]}32c40")); + + meth = class_getInstanceMethod (fooClass, @selector(_attributeRunForCharacterAtIndex:)); + CHECK_IF (!strcmp (meth->method_types, "r^{?=@@QQ^Qffff{_NSRect={_NSPoint=ff}{_NSSize=ff}}q^qQ^Q@@@:::****{?=b1b1b1b1b1b27}}24@0:8Q16")); + + meth = class_getInstanceMethod (fooClass, @selector(_getATSTypesetterGuts:)); + CHECK_IF (!strcmp (meth->method_types, "r@24@0:8r:16")); + + meth = class_getInstanceMethod (fooClass, @selector(resumeWithSuspensionID:and:)); + CHECK_IF (!strcmp (meth->method_types, "v32@0:8^{__NSAppleEventManagerSuspension=}16r^Q24")); + + meth = class_getInstanceMethod (fooClass, @selector(anotherMeth:and:and:)); + CHECK_IF (!strcmp (meth->method_types, "r@40@0:8r:16r@24r@32")); + + meth = class_getInstanceMethod (fooClass, @selector(str1:str2:str3:str4:)); + CHECK_IF (!strcmp (meth->method_types, "@48@0:8r*16*24*32r*40")); + + meth = class_getInstanceMethod (fooClass, @selector(foo1:foo2:foo3:foo4:)); + CHECK_IF (!strcmp (meth->method_types, "Vv48@0:8@16r@24@32r@40")); + + meth = class_getInstanceMethod (fooClass, @selector(sel1:id1:)); + CHECK_IF (!strcmp (meth->method_types, "rn*32@0:8r:16r@24")); + + meth = class_getInstanceMethod (fooClass, @selector(obj1:obj2:obj3:)); + CHECK_IF (!strcmp (meth->method_types, "N@40@0:8r@16@24^{Object=#}32")); + + meth = class_getClassMethod (fooClass, @selector(_defaultScriptingComponent)); + CHECK_IF (!strcmp (meth->method_types, "^{ComponentInstanceRecord=[1q]}16@0:8")); + + meth = class_getInstanceMethod (fooClass, @selector(_formatCocoaErrorString:parameters:applicableFormatters:count:)); + CHECK_IF (!strcmp (meth->method_types, "@44@0:8@16r*24^^{?}32i40")); + + meth = class_getInstanceMethod (fooClass, @selector(formatter_func:run:)); + CHECK_IF (!strcmp (meth->method_types, "^{?=^?@I}32@0:8@16r^^{?}24")); + + meth = class_getInstanceMethod (fooClass, @selector(_forgetWord:inDictionary:)); + CHECK_IF (!strcmp (meth->method_types, "c32@0:8nO@16nO@24")); + + meth = class_getInstanceMethod (fooClass, @selector(_registerServicesMenu:withSendTypes:andReturnTypes:addToList:)); + CHECK_IF (!strcmp (meth->method_types, "v44@0:8@16r^*24r^*32c40")); + + meth = class_getClassMethod (fooClass, @selector(_proxySharePointer)); + CHECK_IF (!strcmp (meth->method_types, "^^{__CFSet}16@0:8")); + + meth = class_getInstanceMethod (fooClass, @selector(_checkGrammarInString:language:details:)); + CHECK_IF (!strcmp (meth->method_types, "{_NSRange=II}40@0:8n@16nO@24oO^@32")); + + meth = class_getInstanceMethod (fooClass, @selector(_resolvePositionalStakeGlyphsForLineFragment:lineFragmentRect:minPosition:maxPosition:maxLineFragmentWidth:breakHint:)); + CHECK_IF (!strcmp (meth->method_types, "B60@0:8^{__CTLine=}16{_NSRect={_NSPoint=ff}{_NSSize=ff}}24f40f44f48^Q52")); + + meth = class_getClassMethod (fooClass, @selector(findVoiceByIdentifier:returningCreator:returningID:)); + CHECK_IF (!strcmp (meth->method_types, "c40@0:8@16^I24^I32")); + + ivars = fooClass->ivars; + CHECK_IF (ivars->ivar_count == 1); + + ivar = ivars->ivar_list; + CHECK_IF (!strcmp (ivar->ivar_name, "r")); + CHECK_IF (!strcmp (ivar->ivar_type, + "{?=\"_attributes\"@\"NSDictionary\"\"_font\"@\"NSFont\"\"_characterLength\"" + "Q\"_nominalGlyphLocation\"Q\"p\"^Q\"_defaultLineHeight\"f\"_defaultBaselineOffset\"" + "f\"_horizExpansion\"f\"_baselineDelta\"f\"_attachmentBBox\"{_NSRect=\"origin\"" + "{_NSPoint=\"x\"f\"y\"f}\"size\"{_NSSize=\"width\"f\"height\"f}}\"ll\"q\"llp\"^q\"ull\"" + "Q\"ullp\"^Q\"a\"@\"a1\"@\"a2\"@\"b\":\"b1\":\"b2\":\"str1\"*\"str2\"*\"str3\"*\"str4\"" + "*\"_rFlags\"{?=\"_isAttachmentRun\"b1\"_hasPositionalStake\"b1\"_isDefaultFace\"" + "b1\"_hasCombiningMarks\"b1\"_isScreenFont\"b1\"_reserved\"b27}}")); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/encode-7-next.m b/gcc/testsuite/objc.dg/encode-7-next.m new file mode 100644 index 0000000..60db236 --- /dev/null +++ b/gcc/testsuite/objc.dg/encode-7-next.m @@ -0,0 +1,267 @@ +/* Additional testing for the NeXT runtime. */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* { dg-do run { target *-*-darwin* } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "-m64" } { "" } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ + +#include "../objc-obj-c++-shared/Object1.h" +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#define CHECK_IF(E) if (!(E)) abort () + +@class NSDictionary, NSFont, NSError, _NSATSTypesetterGuts, NSString, NSMenu, NSArray; + +typedef unsigned char UInt8; +typedef const signed long OSStatus; +typedef unsigned long CFIndex; +typedef unsigned int UInt32; +typedef UInt32 FourCharCode; +typedef FourCharCode OSType; + +struct FSRef { + UInt8 hidden[80]; +}; +typedef struct FSRef FSRef; + +typedef struct _NSPoint { + float x; + float y; +} NSPoint; + +typedef struct _NSSize { + float width; + float height; +} NSSize; + +typedef struct _NSRect { + NSPoint origin; + NSSize size; +} NSRect; + +typedef struct _NSRange { + unsigned int location; + unsigned int length; +} NSRange; + +typedef const char *NXAtom; + +typedef struct { + NSDictionary *_attributes; + NSFont *_font; + CFIndex _characterLength; + CFIndex _nominalGlyphLocation; + const CFIndex *p; + float _defaultLineHeight; + float _defaultBaselineOffset; + float _horizExpansion; + float _baselineDelta; + NSRect _attachmentBBox; + long ll, *llp; + unsigned long ull, *ullp; + id a; + const id a1; + const struct objc_object *a2; + SEL b; + const SEL b1; + const struct objc_selector *b2; + const char *str1; + char *str2; + char *const str3; + const char *const str4; + struct { + unsigned int _isAttachmentRun:1; + unsigned int _hasPositionalStake:1; + unsigned int _isDefaultFace:1; + unsigned int _hasCombiningMarks:1; + unsigned int _isScreenFont:1; + unsigned int _reserved:27; + } _rFlags; +} NSATSGlyphStorageRun; + +typedef struct __CFSet *CFMutableSetRef; +typedef const struct __CTLine * CTLineRef; +typedef const struct __NSAppleEventManagerSuspension* NSAppleEventManagerSuspensionID; + +struct ComponentInstanceRecord { + long data[1]; +}; +typedef struct ComponentInstanceRecord ComponentInstanceRecord; +typedef ComponentInstanceRecord *ComponentInstance; + +typedef NSString *(*NSErrorUserInfoFormatterFunc)(id objToBeDisplayed, NSError *err, char modifier); +typedef struct { + NSErrorUserInfoFormatterFunc formatterFunc; + NSString *userInfoKey; + unsigned int parameterMask; +} NSErrorUserInfoFormatter; + +typedef Object MyObj; +typedef Object *MyPtr; + +@interface Foo: Object { + NSATSGlyphStorageRun r; +} +- (NSError *)_errorWithOSStatus:(OSStatus)inOSStatus ref1:(const FSRef *)inRef1 ref2:(const struct FSRef *)inRef2 + reading:(BOOL)inReadingNotWriting; +- (const NSATSGlyphStorageRun *)_attributeRunForCharacterAtIndex:(const CFIndex)charIndex; +- (const _NSATSTypesetterGuts *)_getATSTypesetterGuts:(const struct objc_selector *)sel; +- (void)resumeWithSuspensionID:(NSAppleEventManagerSuspensionID)suspensionID and:(const CFIndex *)status; +- (const id)anotherMeth:(const SEL)sel and:(const Foo *)foo and:(const struct objc_object *)obj; +- (id)str1:(const char *)str1 str2:(char *)str2 str3:(char *const)str3 str4:(const char *const)str4; +- (oneway void)foo1:(Foo *)foo1 foo2:(const Foo *)foo2 foo3:(Foo *const)foo3 foo4:(const Foo *const)foo4; +- (in const char *)sel1:(const SEL)sel1 id1:(const id)id1; +- (inout id)obj1:(const MyPtr)obj1 obj2:(Object *const)obj2 obj3:(MyObj *const)obj3; ++ (ComponentInstance)_defaultScriptingComponent; +- (NSString *)_formatCocoaErrorString:(NSString *)formatString parameters:(const char *)parameters + applicableFormatters:(NSErrorUserInfoFormatter **)formatters count:(int)numFormatters; +- (NSErrorUserInfoFormatter *)formatter_func:(id)obj run:(const NSATSGlyphStorageRun **)run; +- (BOOL)_forgetWord:(bycopy in NSString *)word inDictionary:(bycopy in NSString *)language; +- (void)_registerServicesMenu:(NSMenu *)servicesMenu withSendTypes:(const NXAtom *)sendTypes + andReturnTypes:(const NXAtom *)returnTypes addToList:(BOOL)addToList; ++ (CFMutableSetRef *)_proxySharePointer; +- (NSRange)_checkGrammarInString:(in NSString *)stringToCheck language:(bycopy in NSString *)language details:(bycopy out NSArray **)details; +- (bool)_resolvePositionalStakeGlyphsForLineFragment:(CTLineRef)line lineFragmentRect:(NSRect)lineFragmentRect + minPosition:(float)minPosition maxPosition:(float)maxPosition maxLineFragmentWidth:(float)maxLineFragmentWidth + breakHint:(CFIndex *)charIndex; ++ (BOOL)findVoiceByIdentifier:(NSString *)identifier returningCreator:(OSType *)returnedCreator returningID:(OSType *)returnedID; +@end + +NSRange globalRange; + +@implementation Foo +- (NSError *)_errorWithOSStatus:(OSStatus)inOSStatus ref1:(const FSRef *)inRef1 ref2:(const struct FSRef *)inRef2 + reading:(BOOL)inReadingNotWriting { + return (NSError *)self; +} +- (const NSATSGlyphStorageRun *)_attributeRunForCharacterAtIndex:(CFIndex)charIndex { + return (const NSATSGlyphStorageRun *)self; +} +- (const _NSATSTypesetterGuts *)_getATSTypesetterGuts:(const struct objc_selector *)sel { + return (const _NSATSTypesetterGuts *)self; +} +- (void)resumeWithSuspensionID:(NSAppleEventManagerSuspensionID)suspensionID and:(const CFIndex *)status { +} +- (const id)anotherMeth:(const SEL)sel and:(const Foo *)foo and:(const struct objc_object *)obj { + return (const id)self; +} +- (id)str1:(const char *)str1 str2:(char *)str2 str3:(char *const)str3 str4:(const char *const)str4 { + return self; +} +- (oneway void)foo1:(Foo *)foo1 foo2:(const Foo *)foo2 foo3:(Foo *const)foo3 foo4:(const Foo *const)foo4 { +} +- (in const char *)sel1:(const SEL)sel1 id1:(const id)id1 { + return "Hello"; +} +- (inout id)obj1:(const MyPtr)obj1 obj2:(Object *const)obj2 obj3:(MyObj *const)obj3 { + return self; +} ++ (ComponentInstance)_defaultScriptingComponent { + return (ComponentInstance)0; +} +- (NSString *)_formatCocoaErrorString:(NSString *)formatString parameters:(const char *)parameters + applicableFormatters:(NSErrorUserInfoFormatter **)formatters count:(int)numFormatters { + return (NSString *)self; +} +- (NSErrorUserInfoFormatter *)formatter_func:(id)obj run:(const NSATSGlyphStorageRun **)run { + return (NSErrorUserInfoFormatter *)0; +} +- (BOOL)_forgetWord:(bycopy in NSString *)word inDictionary:(bycopy in NSString *)language { + return YES; +} +- (void)_registerServicesMenu:(NSMenu *)servicesMenu withSendTypes:(const NXAtom *)sendTypes + andReturnTypes:(const NXAtom *)returnTypes addToList:(BOOL)addToList { +} ++ (CFMutableSetRef *)_proxySharePointer { + return (CFMutableSetRef *)0; +} +- (NSRange)_checkGrammarInString:(in NSString *)stringToCheck language:(bycopy in NSString *)language details:(bycopy out NSArray **)details { + return globalRange; +} +- (bool)_resolvePositionalStakeGlyphsForLineFragment:(CTLineRef)line lineFragmentRect:(NSRect)lineFragmentRect + minPosition:(float)minPosition maxPosition:(float)maxPosition maxLineFragmentWidth:(float)maxLineFragmentWidth + breakHint:(CFIndex *)charIndex { + return false; +} ++ (BOOL)findVoiceByIdentifier:(NSString *)identifier returningCreator:(OSType *)returnedCreator returningID:(OSType *)returnedID { + return NO; +} +@end + +int main(void) { + Class fooClass = objc_getClass ("Foo"); + Method meth; + struct objc_ivar_list *ivars; + struct objc_ivar *ivar; + + meth = class_getInstanceMethod (fooClass, @selector(_errorWithOSStatus:ref1:ref2:reading:)); + CHECK_IF (!strcmp (meth->method_types, "@24@0:4l8r^{FSRef=[80C]}12r^{FSRef=[80C]}16c20")); + + meth = class_getInstanceMethod (fooClass, @selector(_attributeRunForCharacterAtIndex:)); + CHECK_IF (!strcmp (meth->method_types, "r^{?=@@II^Iffff{_NSRect={_NSPoint=ff}{_NSSize=ff}}l^lL^L@@@:::****{?=b1b1b1b1b1b27}}12@0:4L8")); + + meth = class_getInstanceMethod (fooClass, @selector(_getATSTypesetterGuts:)); + CHECK_IF (!strcmp (meth->method_types, "r@12@0:4r:8")); + + meth = class_getInstanceMethod (fooClass, @selector(resumeWithSuspensionID:and:)); + CHECK_IF (!strcmp (meth->method_types, "v16@0:4^{__NSAppleEventManagerSuspension=}8r^I12")); + + meth = class_getInstanceMethod (fooClass, @selector(anotherMeth:and:and:)); + CHECK_IF (!strcmp (meth->method_types, "r@20@0:4r:8r@12r@16")); + + meth = class_getInstanceMethod (fooClass, @selector(str1:str2:str3:str4:)); + CHECK_IF (!strcmp (meth->method_types, "@24@0:4r*8*12*16r*20")); + + meth = class_getInstanceMethod (fooClass, @selector(foo1:foo2:foo3:foo4:)); + CHECK_IF (!strcmp (meth->method_types, "Vv24@0:4@8r@12@16r@20")); + + meth = class_getInstanceMethod (fooClass, @selector(sel1:id1:)); + CHECK_IF (!strcmp (meth->method_types, "rn*16@0:4r:8r@12")); + + meth = class_getInstanceMethod (fooClass, @selector(obj1:obj2:obj3:)); + CHECK_IF (!strcmp (meth->method_types, "N@20@0:4r@8@12^{Object=#}16")); + + meth = class_getClassMethod (fooClass, @selector(_defaultScriptingComponent)); + CHECK_IF (!strcmp (meth->method_types, "^{ComponentInstanceRecord=[1l]}8@0:4")); + + meth = class_getInstanceMethod (fooClass, @selector(_formatCocoaErrorString:parameters:applicableFormatters:count:)); + CHECK_IF (!strcmp (meth->method_types, "@24@0:4@8r*12^^{?}16i20")); + + meth = class_getInstanceMethod (fooClass, @selector(formatter_func:run:)); + CHECK_IF (!strcmp (meth->method_types, "^{?=^?@I}16@0:4@8r^^{?}12")); + + meth = class_getInstanceMethod (fooClass, @selector(_forgetWord:inDictionary:)); + CHECK_IF (!strcmp (meth->method_types, "c16@0:4nO@8nO@12")); + + meth = class_getInstanceMethod (fooClass, @selector(_registerServicesMenu:withSendTypes:andReturnTypes:addToList:)); + CHECK_IF (!strcmp (meth->method_types, "v24@0:4@8r^*12r^*16c20")); + + meth = class_getClassMethod (fooClass, @selector(_proxySharePointer)); + CHECK_IF (!strcmp (meth->method_types, "^^{__CFSet}8@0:4")); + + meth = class_getInstanceMethod (fooClass, @selector(_checkGrammarInString:language:details:)); + CHECK_IF (!strcmp (meth->method_types, "{_NSRange=II}20@0:4n@8nO@12oO^@16")); + + meth = class_getInstanceMethod (fooClass, @selector(_resolvePositionalStakeGlyphsForLineFragment:lineFragmentRect:minPosition:maxPosition:maxLineFragmentWidth:breakHint:)); + CHECK_IF (!strcmp (meth->method_types, "B44@0:4^{__CTLine=}8{_NSRect={_NSPoint=ff}{_NSSize=ff}}12f28f32f36^I40")); + + meth = class_getClassMethod (fooClass, @selector(findVoiceByIdentifier:returningCreator:returningID:)); + CHECK_IF (!strcmp (meth->method_types, "c20@0:4@8^I12^I16")); + + ivars = fooClass->ivars; + CHECK_IF (ivars->ivar_count == 1); + + ivar = ivars->ivar_list; + CHECK_IF (!strcmp (ivar->ivar_name, "r")); + CHECK_IF (!strcmp (ivar->ivar_type, + "{?=\"_attributes\"@\"NSDictionary\"\"_font\"@\"NSFont\"\"_characterLength\"" + "I\"_nominalGlyphLocation\"I\"p\"^I\"_defaultLineHeight\"f\"_defaultBaselineOffset\"" + "f\"_horizExpansion\"f\"_baselineDelta\"f\"_attachmentBBox\"{_NSRect=\"origin\"" + "{_NSPoint=\"x\"f\"y\"f}\"size\"{_NSSize=\"width\"f\"height\"f}}\"ll\"l\"llp\"^l\"ull\"" + "L\"ullp\"^L\"a\"@\"a1\"@\"a2\"@\"b\":\"b1\":\"b2\":\"str1\"*\"str2\"*\"str3\"*\"str4\"" + "*\"_rFlags\"{?=\"_isAttachmentRun\"b1\"_hasPositionalStake\"b1\"_isDefaultFace\"" + "b1\"_hasCombiningMarks\"b1\"_isScreenFont\"b1\"_reserved\"b27}}")); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/proto-qual-1.m b/gcc/testsuite/objc.dg/proto-qual-1.m index 7c6c62d..ac650aa 100644 --- a/gcc/testsuite/objc.dg/proto-qual-1.m +++ b/gcc/testsuite/objc.dg/proto-qual-1.m @@ -44,10 +44,20 @@ static void scan_initial(const char *pattern) { int main(void) { meth = [proto descriptionForInstanceMethod: @selector(address:with:)]; +#ifndef __NEXT_RUNTIME__ scan_initial("O@%u@%u:%uRN@%uo^^S%u"); +#else + /* The NEXT runtime tries to be compatible with gcc-3.3 */ + scan_initial("O@%u@%u:%uNR@%uo^^S%u"); +#endif CHECK_IF(offs3 == offs2 + aligned_sizeof(id) && totsize == offs3 + aligned_sizeof(unsigned)); meth = [proto descriptionForClassMethod: @selector(retainArgument:with:)]; +#ifndef __NEXT_RUNTIME__ scan_initial("Vv%u@%u:%uoO@%un^*%u"); +#else + /* The NEXT runtime tries to be compatible with gcc-3.3 */ + scan_initial("Vv%u@%u:%uOo@%un^*%u"); +#endif CHECK_IF(offs3 == offs2 + aligned_sizeof(id) && totsize == offs3 + aligned_sizeof(char **)); return 0; } diff --git a/gcc/testsuite/objc.dg/threedotthree-abi-1.m b/gcc/testsuite/objc.dg/threedotthree-abi-1.m new file mode 100644 index 0000000..8e4f2be --- /dev/null +++ b/gcc/testsuite/objc.dg/threedotthree-abi-1.m @@ -0,0 +1,68 @@ +/* This file tests that things are encoded using the gcc-3.3 ABI which is only + used by the NeXT runtime. */ +/* { dg-do run { target *-*-darwin* } } */ +/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */ +#include <stdio.h> +#include <string.h> +#include "../objc-obj-c++-shared/Protocol1.h" + +extern void abort(); + + +@protocol CommonProtocol + +-(oneway void)methodCall_On:(in bycopy id)someValue_On; +-(oneway void)methodCall_nO:(bycopy in id)someValue_nO; + +-(oneway void)methodCall_Oo:(out bycopy id)someValue_Oo; +-(oneway void)methodCall_oO:(bycopy out id)someValue_oO; + +-(oneway void)methodCall_rn:(in const id)someValue_rn; + +-(oneway void)methodCall_oOn:(in bycopy out id)someValue_oOn; + +@end + +@interface ObjCClass <CommonProtocol> +{ + +} + +@end + +@implementation ObjCClass +-(oneway void)methodCall_On:(in bycopy id)someValue_On { } +-(oneway void)methodCall_nO:(bycopy in id)someValue_nO { } + +-(oneway void)methodCall_Oo:(out bycopy id)someValue_Oo { } +-(oneway void)methodCall_oO:(bycopy out id)someValue_oO { } + +-(oneway void)methodCall_rn:(in const id)someValue_rn { } +-(oneway void)methodCall_oOn:(in bycopy out id)someValue_oOn { } +@end + +Protocol *proto = @protocol(CommonProtocol); +struct objc_method_description *meth; + +int main() +{ + meth = [proto descriptionForInstanceMethod: @selector(methodCall_On:)]; + if (strcmp (meth->types, "Vv12@0:4On@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_nO:)]; + if (strcmp (meth->types, "Vv12@0:4nO@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_Oo:)]; + if (strcmp (meth->types, "Vv12@0:4Oo@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_oO:)]; + if (strcmp (meth->types, "Vv12@0:4oO@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_rn:)]; + if (strcmp (meth->types, "Vv12@0:4rn@8")) + abort(); + meth = [proto descriptionForInstanceMethod: @selector(methodCall_oOn:)]; + if (strcmp (meth->types, "Vv12@0:4oOn@8")) + abort(); + return 0; +} diff --git a/gcc/testsuite/objc.dg/type-size-2.m b/gcc/testsuite/objc.dg/type-size-2.m index 2f8d517..499f083 100644 --- a/gcc/testsuite/objc.dg/type-size-2.m +++ b/gcc/testsuite/objc.dg/type-size-2.m @@ -48,7 +48,20 @@ int main(void) { cls = objc_get_class("ArrayTest"); meth = class_get_instance_method(cls, @selector(str:with:and:)); - scan_initial("r*%u@%u:%u*%u*%u[4i]%u"); + + /* Here we have the complication that 'enum Enum' could be encoded + as 'i' on __NEXT_RUNTIME_, and (most likely) as 'I' on the GNU + runtime. So we get the @encode(enum Enum), then put it into the + string in place of the traditional 'i'. + */ + /* scan_initial("r*%u@%u:%u*%u*%u[4i]%u"); */ + { + char pattern[1024]; + + sprintf (pattern, "r*%%u@%%u:%%u*%%u*%%u[4%s]%%u", @encode(enum Enum)); + scan_initial(pattern); + } + CHECK_IF(offs3 == offs2 + sizeof(signed char *) && offs4 == offs3 + sizeof(unsigned char *)); CHECK_IF(totsize == offs4 + sizeof(enum Enum *)); meth = class_get_instance_method(cls, @selector(meth1:with:with:)); diff --git a/gcc/testsuite/objc.dg/type-size-3.m b/gcc/testsuite/objc.dg/type-size-3.m new file mode 100644 index 0000000..9486658 --- /dev/null +++ b/gcc/testsuite/objc.dg/type-size-3.m @@ -0,0 +1,18 @@ +/* Reject ivars with an unknown size. */ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com> */ +/* { dg-do compile } */ + +typedef struct +{ + unsigned long int a; + double b[]; +} test_type; + +@interface Test +{ + test_type c; +} +@end + +@implementation Test +@end /* { dg-error "instance variable has unknown size" } */ diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog index f9d9925..029b0a3 100644 --- a/libobjc/ChangeLog +++ b/libobjc/ChangeLog @@ -1,5 +1,15 @@ 2010-09-26 Nicola Pero <nicola.pero@meta-innovation.com> + * encoding.c (objc_sizeof_type): Added support for vector type and + for double long types. + (objc_alignof_type): Same change. + (objc_skip_typespec): Same change. + * objc/encoding.h (_C_GCINVISIBLE): Use '|' for _C_GCINVISIBLE + instead of '!' since '!' is already used for _C_VECTOR. + * objc/objc-api.h (_C_LNG_DBL): Added. + +2010-09-26 Nicola Pero <nicola.pero@meta-innovation.com> + * libobjc_entry.c: File removed. 2010-09-26 Kai Tietz <kai.tietz@onevision.com> diff --git a/libobjc/encoding.c b/libobjc/encoding.c index 35c9552..d417b87 100644 --- a/libobjc/encoding.c +++ b/libobjc/encoding.c @@ -148,6 +148,8 @@ objc_sizeof_type (const char *type) /* Skip the variable name if any */ if (*type == '"') { + /* FIXME: How do we know we won't read beyond the end of the + string. Here and in the rest of the file! */ for (type++; *type++ != '"';) /* do nothing */; } @@ -217,6 +219,10 @@ objc_sizeof_type (const char *type) return sizeof (double); break; + case _C_LNG_DBL: + return sizeof (long double); + break; + case _C_VOID: return sizeof (void); break; @@ -236,6 +242,19 @@ objc_sizeof_type (const char *type) } break; + case _C_VECTOR: + { + /* Skip the '!'. */ + type++; + /* Skip the '['. */ + type++; + + /* The size in bytes is the following number. */ + int size = atoi (type); + return size; + } + break; + case _C_BFLD: { /* The new encoding of bitfields is: b 'position' 'type' 'size' */ @@ -318,6 +337,10 @@ objc_sizeof_type (const char *type) case _C_DBL: return sizeof (_Complex double); break; + + case _C_LNG_DBL: + return sizeof (_Complex long double); + break; default: { @@ -418,6 +441,10 @@ objc_alignof_type (const char *type) return __alignof__ (double); break; + case _C_LNG_DBL: + return __alignof__ (long double); + break; + case _C_PTR: case _C_ATOM: case _C_CHARPTR: @@ -429,6 +456,23 @@ objc_alignof_type (const char *type) /* do nothing */; return objc_alignof_type (type); + case _C_VECTOR: + { + /* Skip the '!'. */ + type++; + /* Skip the '['. */ + type++; + + /* Skip the size. */ + while (isdigit ((unsigned char)*type)) + type++; + + /* Skip the ','. */ + type++; + + /* The alignment in bytes is the following number. */ + return atoi (type); + } case _C_STRUCT_B: case _C_UNION_B: { @@ -496,6 +540,10 @@ objc_alignof_type (const char *type) case _C_DBL: return __alignof__ (_Complex double); break; + + case _C_LNG_DBL: + return __alignof__ (_Complex long double); + break; default: { @@ -631,6 +679,7 @@ objc_skip_typespec (const char *type) case _C_ULNG_LNG: case _C_FLT: case _C_DBL: + case _C_LNG_DBL: case _C_VOID: case _C_UNDEF: return ++type; @@ -642,7 +691,6 @@ objc_skip_typespec (const char *type) case _C_ARY_B: /* skip digits, typespec and closing ']' */ - while (isdigit ((unsigned char)*++type)) ; type = objc_skip_typespec (type); @@ -654,6 +702,30 @@ objc_skip_typespec (const char *type) return 0; } + case _C_VECTOR: + /* Skip '!' */ + type++; + /* Skip '[' */ + type++; + /* Skip digits (size) */ + while (isdigit ((unsigned char)*type)) + type++; + /* Skip ',' */ + type++; + /* Skip digits (alignment) */ + while (isdigit ((unsigned char)*type)) + type++; + /* Skip typespec. */ + type = objc_skip_typespec (type); + /* Skip closing ']'. */ + if (*type == _C_ARY_E) + return ++type; + else + { + _objc_abort ("bad vector type %s\n", type); + return 0; + } + case _C_BFLD: /* The new encoding of bitfields is: b 'position' 'type' 'size' */ while (isdigit ((unsigned char)*++type)) @@ -700,6 +772,8 @@ objc_skip_typespec (const char *type) /* Skip an offset as part of a method encoding. This is prepended by a '+' if the argument is passed in registers. + + FIXME: The compiler never generates '+'. */ const char * objc_skip_offset (const char *type) @@ -883,7 +957,7 @@ objc_get_type_qualifiers (const char *type) the presence of bitfields inside the structure. */ void objc_layout_structure (const char *type, - struct objc_struct_layout *layout) + struct objc_struct_layout *layout) { const char *ntype; @@ -979,6 +1053,7 @@ objc_layout_structure_next_member (struct objc_struct_layout *layout) bfld_field_size = atoi (objc_skip_typespec (bfld_type)); } + /* The following won't work for vectors. */ #ifdef BIGGEST_FIELD_ALIGNMENT desired_align = MIN (desired_align, BIGGEST_FIELD_ALIGNMENT); #endif diff --git a/libobjc/objc/encoding.h b/libobjc/objc/encoding.h index 0deae5f..177ef72 100644 --- a/libobjc/objc/encoding.h +++ b/libobjc/objc/encoding.h @@ -42,7 +42,7 @@ extern "C" { #define _C_BYCOPY 'O' #define _C_BYREF 'R' #define _C_ONEWAY 'V' -#define _C_GCINVISIBLE '!' +#define _C_GCINVISIBLE '|' #define _F_CONST 0x01 #define _F_IN 0x01 diff --git a/libobjc/objc/objc-api.h b/libobjc/objc/objc-api.h index 9903739..be433cb 100644 --- a/libobjc/objc/objc-api.h +++ b/libobjc/objc/objc-api.h @@ -68,13 +68,13 @@ struct objc_method_description #define _C_ULNG_LNG 'Q' #define _C_FLT 'f' #define _C_DBL 'd' +#define _C_LNG_DBL 'D' #define _C_BFLD 'b' -#define _C_BOOL 'B' +#define _C_BOOL 'B' #define _C_VOID 'v' #define _C_UNDEF '?' #define _C_PTR '^' #define _C_CHARPTR '*' -#define _C_ATOM '%' #define _C_ARY_B '[' #define _C_ARY_E ']' #define _C_UNION_B '(' @@ -82,7 +82,13 @@ struct objc_method_description #define _C_STRUCT_B '{' #define _C_STRUCT_E '}' #define _C_VECTOR '!' -#define _C_COMPLEX 'j' +#define _C_COMPLEX 'j' + +/* The following one is never generated by the compiler. You can + treat it as equivalent to "*". +*/ +#define _C_ATOM '%' + #include "deprecated/objc_error.h" |