Fixed check for flexible array members used in Objective-C instance variables
authorNicola Pero <nicola.pero@meta-innovation.com>
Tue, 22 Feb 2011 18:30:44 +0000 (18:30 +0000)
committerNicola Pero <nicola@gcc.gnu.org>
Tue, 22 Feb 2011 18:30:44 +0000 (18:30 +0000)
From-SVN: r170412

gcc/objc/ChangeLog
gcc/objc/objc-act.c
gcc/testsuite/ChangeLog
gcc/testsuite/objc.dg/type-size-3.m
gcc/testsuite/objc.dg/type-size-4.m [new file with mode: 0644]
gcc/testsuite/objc.dg/type-size-5.m [new file with mode: 0644]

index a7b21c322c0fa8b554d3cc0ab563add56647c1c7..9c466aa8771e7aab45739a785d0659cd65ddfc15 100644 (file)
@@ -1,13 +1,22 @@
+2011-02-22  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       PR objc/47832
+       * objc-act.c (flexible_array_type_p): New.
+       (add_instance_variable): Produce an error if an instance variable
+       uses flexible array members.
+       (encode_array): Do not emit an error if encoding a flexible array
+       type while generating instance variables.
+
 2011-02-21  Mike Stump  <mikestump@comcast.net>
 
        * Make-lang.in (check_objc_parallelize): Refine for 4 processor machines.
 
 2011-02-20  Nicola Pero  <nicola.pero@meta-innovation.com>
 
-       * objc-gnu-runtime-abi-01.c (TARGET_64BIT): Removed.  Removed
-       usage of padding fields.  Do not include tm.h.
-       * objc-act.c (objc_write_global_declaration): Set input_location
-       to BUILTINS_LOCATION while generating runtime metadata.
+       * objc-gnu-runtime-abi-01.c (TARGET_64BIT): Removed.  Removed
+       usage of padding fields.  Do not include tm.h.
+       * objc-act.c (objc_write_global_declaration): Set input_location
+       to BUILTINS_LOCATION while generating runtime metadata.
 
 2011-01-20  Nicola Pero  <nicola.pero@meta-innovation.com>
 
index a91c7083173b4193f007459c4a475b1d989e5104..85ef8fb0526d55edcfc13c7bb71a06de6802c386 100644 (file)
@@ -5925,6 +5925,58 @@ add_category (tree klass, tree category)
     }
 }
 
+#ifndef OBJCPLUS
+/* A flexible array member is a C99 extension where you can use
+   "type[]" at the end of a struct to mean a variable-length array.
+
+   In Objective-C, instance variables are fundamentally members of a
+   struct, but the struct can always be extended by subclassing; hence
+   we need to detect and forbid all instance variables declared using
+   flexible array members.
+
+   No check for this is needed in Objective-C++, since C++ does not
+   have flexible array members.  */
+
+/* Determine whether TYPE is a structure with a flexible array member,
+   a union containing such a structure (possibly recursively) or an
+   array of such structures or unions.  These are all invalid as
+   instance variable.  */
+static bool
+flexible_array_type_p (tree type)
+{
+  tree x;
+  switch (TREE_CODE (type))
+    {
+    case RECORD_TYPE:
+      x = TYPE_FIELDS (type);
+      if (x == NULL_TREE)
+       return false;
+      while (DECL_CHAIN (x) != NULL_TREE)
+       x = DECL_CHAIN (x);
+      if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
+         && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
+         && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE
+         && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE)
+       return true;
+      return false;
+    case UNION_TYPE:
+      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
+       {
+         if (flexible_array_type_p (TREE_TYPE (x)))
+           return true;
+       }
+      return false;
+    /* Note that we also check for arrays of something that uses a flexible array member.  */
+    case ARRAY_TYPE:
+      if (flexible_array_type_p (TREE_TYPE (type)))
+       return true;
+      return false;
+    default:
+    return false;
+  }
+}
+#endif
+
 /* Called after parsing each instance variable declaration. Necessary to
    preserve typedefs and implement public/private...
 
@@ -5958,6 +6010,27 @@ add_instance_variable (tree klass, objc_ivar_visibility_kind visibility,
       return klass;
     }
 
+#ifndef OBJCPLUS
+  /* Also, in C reject a struct with a flexible array member.  Ie,
+
+       struct A { int x; int[] y; };
+
+       @interface X
+       {
+         struct A instance_variable;
+       }
+       @end
+
+       is not valid because if the class is subclassed, we wouldn't be able
+       to calculate the offset of the next instance variable.  */
+  if (flexible_array_type_p (field_type))
+    {
+      error ("instance variable %qs uses flexible array member", ivar_name);
+      /* Return class as is without adding this ivar.  */
+      return klass;      
+    }
+#endif
+
 #ifdef OBJCPLUS
   /* Check if the ivar being added has a non-POD C++ type.   If so, we will
      need to either (1) warn the user about it or (2) generate suitable
@@ -9926,27 +9999,23 @@ encode_array (tree type, int curtype, int format)
   if (an_int_cst == NULL)
     {
       /* 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;
-       }
+        array is forbidden as part of an instance variable; but it
+        may occur if the instance variable is a pointer to such an
+        array.  */
 
-      /* 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.
+      /* So the only case in which an incomplete array could occur
+        (without being pointed to) 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.
index 33c8ddeefad527d0382d99872696a7269949f155..32604613064dcfba15b000a3105359d7651f8bcd 100644 (file)
@@ -1,3 +1,10 @@
+2011-02-22  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       PR objc/47832
+       * objc.dg/type-size-3.m: Updated error message.
+       * objc.dg/type-size-4.m: New test.
+       * objc.dg/type-size-5.m: New test.
+
 2011-02-22  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * lib/gnat.exp: Fix comments.
index 6d7fe038447c303401fd8e59f5def43000596209..bc66b0be67a001cd7ffa3e2764efac53c09dd3df 100644 (file)
@@ -1,4 +1,4 @@
-/* Reject ivars with an unknown size.  */
+/* Reject ivars that use flexible array members.  */
 /* Contributed by Nicola Pero  <nicola.pero@meta-innovation.com> */
 /* { dg-do compile } */
 
@@ -10,11 +10,9 @@ typedef struct
 
 @interface Test
 {
-  test_type c;
+  test_type c; /* { dg-error "instance variable .c. uses flexible array member" } */
 }
 @end
 
 @implementation Test
 @end
-
-/* { dg-error "instance variable has unknown size" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/objc.dg/type-size-4.m b/gcc/testsuite/objc.dg/type-size-4.m
new file mode 100644 (file)
index 0000000..7e26da3
--- /dev/null
@@ -0,0 +1,23 @@
+/* Allow ivars that are pointers to structs with an unknown size.  */
+/* Contributed by Nicola Pero  <nicola.pero@meta-innovation.com> */
+/* PR objc/47832 */
+/* { dg-do compile } */
+
+typedef struct
+{
+  unsigned long int a;
+  double b[];
+} test_type;
+
+@interface Test
+{
+  /* These are all fine.  */
+  double *a;
+  struct { int x; double y[]; } *b;
+  test_type *c;
+  union union_type { int x; test_type y; } *d;
+}
+@end
+
+@implementation Test
+@end
diff --git a/gcc/testsuite/objc.dg/type-size-5.m b/gcc/testsuite/objc.dg/type-size-5.m
new file mode 100644 (file)
index 0000000..d89af32
--- /dev/null
@@ -0,0 +1,22 @@
+/* Reject ivars that use flexible array members.  */
+/* Contributed by Nicola Pero  <nicola.pero@meta-innovation.com> */
+/* { dg-do compile } */
+
+typedef struct
+{
+  unsigned long int a;
+  double b[];
+} test_type;
+
+@interface Test
+{
+  double a[];                                 /* { dg-error "instance variable .a. has unknown size" } */
+  struct { int x; double y[]; } b;            /* { dg-error "instance variable .b. uses flexible array member" } */
+  test_type c;                                /* { dg-error "instance variable .c. uses flexible array member" } */
+  test_type d[4];                             /* { dg-error "instance variable .d. uses flexible array member" } */
+  union union_type { int x; test_type y; } e; /* { dg-error "instance variable .e. uses flexible array member" } */
+}
+@end
+
+@implementation Test
+@end