This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH: Fix for long-standing ObjC bitfield "promotion" problem


Ok, so it turned out that this could be fixed without messing
with stor-layout.c. :-)

The essence of the fix is to have each ObjC class store,
in a separate list, a list of its own (i.e., not inherited)
ivars that is kept from ever being side-effected by other
routines in the compiler (most notably finish_struct).
This list is then copied as needed.

The patch comes with two test cases. The first tests
the layout of bitfield ivars within the class; the
second the @encode strings generated by them. Note that
the second test case applies only to the NeXT runtime.
The GNU runtime appears to have a different encoding
scheme, which I don't understand; the GNUStep folks will
have to take it from here.

Bootstrapped and tested on i686-pc-linux-gnu, no regressions.
Since this is a legitimate bug fix, I posit this should go
into TOT. Stan? :-)


[gcc/ChangeLog]

2002-08-18 Ziemowit Laski <zlaski@apple.com>

* objc/objc-act.c (build_ivar_chain): Remove.
(objc_copy_list): Likewise.
(get_class_ivars): Inline call to removed build_ivar_chain
function. Save off a clean copy of ivars in the CLASS_OWN_IVARS
slot; use that slot (rather than CLASS_IVARS) when accessing
ivars for base classes. Call copy_list and chainon instead of
objc_copy_list.
(build_private_template): Call get_class_ivars instead of
build_ivar_chain.
(start_class): Allocate room for the CLASS_OWN_IVARS slot.
(continue_class): Call get_class_ivars instead of
build_ivar_chain.
(encode_field_decl): Check for DECL_BIT_FIELD_TYPE instead
of DECL_BIT_FIELD (which may have been cleared).
* objc/objc-act.h (CLASS_OWN_IVARS): New accessor macro.

[gcc/testsuite/ChangeLog]

2002-08-18 Ziemowit Laski <zlaski@apple.com>

* objc.dg/bitfield-1.m: New test.
* objc.dg/bitfield-2.m: New test.


Index: gcc/objc/objc-act.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.150
diff -c -3 -p -r1.150 objc-act.c
*** gcc/objc/objc-act.c 10 Aug 2002 02:18:27 -0000 1.150
--- gcc/objc/objc-act.c 18 Aug 2002 21:37:53 -0000
*************** static tree build_objc_method_call PARA
*** 128,134 ****
static void generate_strings PARAMS ((void));
static tree get_proto_encoding PARAMS ((tree));
static void build_selector_translation_table PARAMS ((void));
- static tree build_ivar_chain PARAMS ((tree, int));

static tree objc_add_static_instance PARAMS ((tree, tree));

--- 128,133 ----
*************** static tree build_typed_selector_referen
*** 249,255 ****
static tree build_selector_reference PARAMS ((tree));
static tree build_class_reference_decl PARAMS ((void));
static void add_class_reference PARAMS ((tree));
- static tree objc_copy_list PARAMS ((tree, tree *));
static tree build_protocol_template PARAMS ((void));
static tree build_descriptor_table_initializer PARAMS ((tree, tree));
static tree build_method_prototype_list_template PARAMS ((tree, int));
--- 248,253 ----
*************** lookup_interface (ident)
*** 2277,2327 ****
return NULL_TREE;
}

! static tree
! objc_copy_list (list, head)
! tree list;
! tree *head;
! {
! tree newlist = NULL_TREE, tail = NULL_TREE;
!
! while (list)
! {
! tail = copy_node (list);
!
! /* The following statement fixes a bug when inheriting instance
! variables that are declared to be bitfields. finish_struct
! expects to find the width of the bitfield in DECL_INITIAL. */
! if (DECL_BIT_FIELD (tail) && DECL_INITIAL (tail) == 0)
! DECL_INITIAL (tail) = DECL_SIZE (tail);
!
! newlist = chainon (newlist, tail);
! list = TREE_CHAIN (list);
! }
!
! *head = newlist;
! return tail;
! }
!
! /* Used by: build_private_template, get_class_ivars, and
! continue_class. COPY is 1 when called from @defs. In this case
! copy all fields. Otherwise don't copy leaf ivars since we rely on
! them being side-effected exactly once by finish_struct. */

! static tree
! build_ivar_chain (interface, copy)
tree interface;
- int copy;
{
tree my_name, super_name, ivar_chain;

my_name = CLASS_NAME (interface);
super_name = CLASS_SUPER_NAME (interface);

! /* Possibly copy leaf ivars. */
! if (copy)
! objc_copy_list (CLASS_IVARS (interface), &ivar_chain);
! else
! ivar_chain = CLASS_IVARS (interface);

while (super_name)
{
--- 2275,2297 ----
return NULL_TREE;
}

! /* Used by: build_private_template, get_class_ivars, continue_class,
! and for @defs constructs. */

! tree
! get_class_ivars (interface)
tree interface;
{
tree my_name, super_name, ivar_chain;

my_name = CLASS_NAME (interface);
super_name = CLASS_SUPER_NAME (interface);
+ ivar_chain = CLASS_IVARS (interface);

! /* Save off a pristine copy of the leaf ivars (i.e, those not
! inherited from a super class). */
! if (!CLASS_OWN_IVARS (interface))
! CLASS_OWN_IVARS (interface) = copy_list (ivar_chain);

while (super_name)
{
*************** build_ivar_chain (interface, copy)
*** 2345,2358 ****
my_name = CLASS_NAME (interface);
super_name = CLASS_SUPER_NAME (interface);

! op1 = CLASS_IVARS (interface);
if (op1)
{
! tree head, tail = objc_copy_list (op1, &head);

/* Prepend super class ivars...make a copy of the list, we
do not want to alter the original. */
! TREE_CHAIN (tail) = ivar_chain;
ivar_chain = head;
}
}
--- 2315,2328 ----
my_name = CLASS_NAME (interface);
super_name = CLASS_SUPER_NAME (interface);

! op1 = CLASS_OWN_IVARS (interface);
if (op1)
{
! tree head = copy_list (op1);

/* Prepend super class ivars...make a copy of the list, we
do not want to alter the original. */
! chainon (head, ivar_chain);
ivar_chain = head;
}
}
*************** build_private_template (class)
*** 2379,2385 ****
{
uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class));

! ivar_context = build_ivar_chain (class, 0);

finish_struct (uprivate_record, ivar_context, NULL_TREE);

--- 2349,2355 ----
{
uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class));

! ivar_context = get_class_ivars (class);

finish_struct (uprivate_record, ivar_context, NULL_TREE);

*************** is_public (expr, identifier)
*** 5660,5677 ****

return 1;
}
-
- /* Implement @defs (<classname>) within struct bodies. */
-
- tree
- get_class_ivars (interface)
- tree interface;
- {
- /* Make sure we copy the leaf ivars in case @defs is used in a local
- context. Otherwise finish_struct will overwrite the layout info
- using temporary storage. */
- return build_ivar_chain (interface, 1);
- }


/* Make sure all entries in CHAIN are also in LIST. */

--- 5630,5635 ----
*************** start_class (code, class_name, super_nam
*** 5903,5909 ****
}

class = make_node (code);
! TYPE_BINFO (class) = make_tree_vec (5);

CLASS_NAME (class) = class_name;
CLASS_SUPER_NAME (class) = super_name;
--- 5861,5867 ----
}

class = make_node (code);
! TYPE_BINFO (class) = make_tree_vec (6);

CLASS_NAME (class) = class_name;
CLASS_SUPER_NAME (class) = super_name;
*************** continue_class (class)
*** 6093,6099 ****

if (!TYPE_FIELDS (record))
{
! finish_struct (record, build_ivar_chain (class, 0), NULL_TREE);
CLASS_STATIC_TEMPLATE (class) = record;

/* Mark this record as a class template for static typing. */
--- 6051,6057 ----

if (!TYPE_FIELDS (record))
{
! finish_struct (record, get_class_ivars (class), NULL_TREE);
CLASS_STATIC_TEMPLATE (class) = record;

/* Mark this record as a class template for static typing. */
*************** encode_field_decl (field_decl, curtype,
*** 6717,6730 ****
the bitfield typing information. */
if (flag_next_runtime)
{
! if (DECL_BIT_FIELD (field_decl))
encode_bitfield (tree_low_cst (DECL_SIZE (field_decl), 1));
else
encode_type (TREE_TYPE (field_decl), curtype, format);
}
else
{
! if (DECL_BIT_FIELD (field_decl))
encode_complete_bitfield (int_bit_position (field_decl),
DECL_BIT_FIELD_TYPE (field_decl),
tree_low_cst (DECL_SIZE (field_decl), 1));
--- 6675,6688 ----
the bitfield typing information. */
if (flag_next_runtime)
{
! if (DECL_BIT_FIELD_TYPE (field_decl))
encode_bitfield (tree_low_cst (DECL_SIZE (field_decl), 1));
else
encode_type (TREE_TYPE (field_decl), curtype, format);
}
else
{
! if (DECL_BIT_FIELD_TYPE (field_decl))
encode_complete_bitfield (int_bit_position (field_decl),
DECL_BIT_FIELD_TYPE (field_decl),
tree_low_cst (DECL_SIZE (field_decl), 1));
Index: gcc/objc/objc-act.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.h,v
retrieving revision 1.12
diff -c -3 -p -r1.12 objc-act.h
*** gcc/objc/objc-act.h 7 Aug 2002 18:32:11 -0000 1.12
--- gcc/objc/objc-act.h 18 Aug 2002 21:37:55 -0000
*************** tree build_encode_expr PARAMS ((tree)
*** 97,102 ****
--- 97,103 ----
#define CLASS_STATIC_TEMPLATE(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 2)
#define CLASS_CATEGORY_LIST(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 3)
#define CLASS_PROTOCOL_LIST(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 4)
+ #define CLASS_OWN_IVARS(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 5)
#define PROTOCOL_NAME(CLASS) ((CLASS)->type.name)
#define PROTOCOL_LIST(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 0)
#define PROTOCOL_NST_METHODS(CLASS) ((CLASS)->type.minval)
Index: gcc/testsuite/objc.dg/bitfield-1.m
===================================================================
RCS file: gcc/testsuite/objc.dg/bitfield-1.m
diff -N gcc/testsuite/objc.dg/bitfield-1.m
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/objc.dg/bitfield-1.m 18 Aug 2002 21:37:56 -0000
***************
*** 0 ****
--- 1,80 ----
+ /* Check if bitfield ivars are inherited correctly (i.e., without
+ being "promoted" to ints). */
+ /* Contributed by Ziemowit Laski <zlaski@apple.com>. */
+ /* { dg-do run } */
+
+ #include <objc/objc.h>
+ #include <objc/Object.h>
+
+ extern void abort(void);
+
+ #define CHECK_IF(expr) if(!(expr)) abort();
+
+ @interface Base: Object
+ {
+ int full;
+ int full2: 32;
+ int _refs: 8;
+ int field2: 3;
+ unsigned f3: 8;
+ short cc;
+ unsigned g: 16;
+ int r2: 8;
+ int r3: 8;
+ int r4: 2;
+ int r5: 8;
+ char c;
+ }
+ - (void)setValues;
+ @end
+
+ @interface Derived: Base
+ {
+ char d;
+ int _field3: 6;
+ }
+ - (void)checkValues;
+ @end
+
+ @implementation Base
+ -(void)setValues {
+ full = 1;
+ full2 = 2;
+ _refs = 3;
+ field2 = 1;
+ f3 = 6;
+ cc = 7;
+ g = 8;
+ r2 = 9;
+ r3 = 10;
+ r4 = 1;
+ r5 = 12;
+ c = 13;
+ }
+ @end
+
+ @implementation Derived
+ -(void)checkValues {
+ CHECK_IF(full == 1);
+ CHECK_IF(full2 == 2);
+ CHECK_IF(_refs == 3);
+ CHECK_IF(field2 == 1);
+ CHECK_IF(f3 == 6);
+ CHECK_IF(cc == 7);
+ CHECK_IF(g == 8);
+ CHECK_IF(r2 == 9);
+ CHECK_IF(r3 == 10);
+ CHECK_IF(r4 == 1);
+ CHECK_IF(r5 == 12);
+ CHECK_IF(c == 13);
+ }
+ @end
+
+ int main(void) {
+ Derived *obj = [[Derived alloc] init];
+
+ [obj setValues];
+ [obj checkValues];
+
+ return 0;
+ }
Index: gcc/testsuite/objc.dg/bitfield-2.m
===================================================================
RCS file: gcc/testsuite/objc.dg/bitfield-2.m
diff -N gcc/testsuite/objc.dg/bitfield-2.m
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/objc.dg/bitfield-2.m 18 Aug 2002 21:37:57 -0000
***************
*** 0 ****
--- 1,55 ----
+ /* Check if bitfield ivars are correctly @encode'd when
+ the NeXT runtime is used. */
+ /* Contributed by Ziemowit Laski <zlaski@apple.com>. */
+ /* { dg-options "-fnext-runtime" } */
+ /* { dg-do run } */
+
+ struct objc_object { struct objc_class *class_pointer; } *id;
+
+ extern void abort(void);
+ extern int strcmp(const char *, const char *);
+
+ #define CHECK_IF(expr) if(!(expr)) abort();
+
+ @interface Base
+ {
+ struct objc_class *isa;
+ int full;
+ int full2: 32;
+ int _refs: 8;
+ int field2: 3;
+ unsigned f3: 8;
+ short cc;
+ unsigned g: 16;
+ int r2: 8;
+ int r3: 8;
+ int r4: 2;
+ int r5: 8;
+ char c;
+ }
+ @end
+
+ @interface Derived: Base
+ {
+ char d;
+ int _field3: 6;
+ }
+ @end
+
+ @implementation Base
+ @end
+
+ @implementation Derived
+ @end
+
+ int main(void) {
+ const char *s1r = "{Base=#ib32b8b3b8sb16b8b8b2b8c}";
+ const char *s1 = @encode(Base);
+ const char *s2r = "{Derived=#ib32b8b3b8sb16b8b8b2b8ccb6}";
+ const char *s2 = @encode(Derived);
+
+ CHECK_IF(!strcmp(s1r, s1));
+ CHECK_IF(!strcmp(s2r, s2));
+
+ return 0;
+ }

--------------------------------------------------------------
Ziemowit Laski 1 Infinite Loop, MS 301-2K
Mac OS X Compiler Group Cupertino, CA USA 95014-2083
Apple Computer, Inc. +1.408.974.6229 Fax .5477


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]