In gcc/objc/: 2010-11-03 Nicola Pero <nicola.pero@meta-innovation.com>
authorNicola Pero <nicola.pero@meta-innovation.com>
Wed, 3 Nov 2010 10:39:15 +0000 (10:39 +0000)
committerNicola Pero <nicola@gcc.gnu.org>
Wed, 3 Nov 2010 10:39:15 +0000 (10:39 +0000)
In gcc/objc/:
2010-11-03  Nicola Pero  <nicola.pero@meta-innovation.com>

        * objc-act.c (maybe_make_artificial_property_decl): New.
        (objc_maybe_build_component_ref): Call
        maybe_make_artificial_property_decl if a property can not be
        found.  Do not call objc_finish_message_expr if
        PROPERTY_HAS_NO_GETTER.
        * objc-act.h Updated comments.
        (PROPERTY_HAS_NO_GETTER): New.
        (PROPERTY_HAS_NO_SETTER): New.
        * objc-tree.def: Updated comment.

In gcc/testsuite/:
2010-11-03  Nicola Pero  <nicola.pero@meta-innovation.com>

        * objc.dg/property/dotsyntax-1.m: New.
        * objc.dg/property/dotsyntax-2.m: New.
        * obj-c++.dg/property/dotsyntax-1.mm: New.
        * obj-c++.dg/property/dotsyntax-2.mm: New.

From-SVN: r166237

gcc/objc/ChangeLog
gcc/objc/objc-act.c
gcc/objc/objc-act.h
gcc/objc/objc-tree.def
gcc/testsuite/ChangeLog
gcc/testsuite/obj-c++.dg/property/dotsyntax-1.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/property/dotsyntax-2.mm [new file with mode: 0644]
gcc/testsuite/objc.dg/property/dotsyntax-1.m [new file with mode: 0644]
gcc/testsuite/objc.dg/property/dotsyntax-2.m [new file with mode: 0644]

index e9e559214a2701c7a6b02cdd84cb0e6acdff0011..1d78c0c8c2fc51df735b0e0fa481cb5b2087cdee 100644 (file)
@@ -1,3 +1,15 @@
+2010-11-03  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       * objc-act.c (maybe_make_artificial_property_decl): New.
+       (objc_maybe_build_component_ref): Call
+       maybe_make_artificial_property_decl if a property can not be
+       found.  Do not call objc_finish_message_expr if
+       PROPERTY_HAS_NO_GETTER.
+       * objc-act.h Updated comments.
+       (PROPERTY_HAS_NO_GETTER): New.
+       (PROPERTY_HAS_NO_SETTER): New.
+       * objc-tree.def: Updated comment.
+       
 2010-11-01  Nicola Pero  <nicola.pero@meta-innovation.com>
 
        Implemented format and noreturn attributes for Objective-C methods.
index 768215e7257a0dc2b42b4850f50e983bc667e569..cfbcb3c6826c155f6518a8b26d1e4102aac3c15b 100644 (file)
@@ -1053,16 +1053,102 @@ lookup_property (tree interface_type, tree property)
   return inter;
 }
 
+/* This is a subroutine of objc_maybe_build_component_ref.  Search the
+   list of methods in the interface (and, failing that, protocol list)
+   provided for a 'setter' or 'getter' for 'component' with default
+   names (ie, if 'component' is "name", then search for "name" and
+   "setName:").  If any is found, then create an artificial property
+   that uses them.  Return NULL_TREE if 'getter' or 'setter' could not
+   be found.  */
+static tree
+maybe_make_artificial_property_decl (tree interface, tree protocol_list, tree component, bool is_class)
+{
+  tree getter_name = component;
+  tree setter_name = get_identifier (objc_build_property_setter_name (component));
+  tree getter = NULL_TREE;
+  tree setter = NULL_TREE;
+
+  if (interface)
+    {
+      int flags = 0;
+
+      if (is_class)
+       flags = OBJC_LOOKUP_CLASS;
+      
+      getter = lookup_method_static (interface, getter_name, flags);
+      setter = lookup_method_static (interface, setter_name, flags);
+    }
+
+  /* Try the protocol_list if we didn't find anything in the interface.  */
+  if (!getter && !setter)
+    {
+      getter = lookup_method_in_protocol_list (protocol_list, getter_name, is_class);
+      setter = lookup_method_in_protocol_list (protocol_list, setter_name, is_class);
+    }
+
+  /* There needs to be at least a getter or setter for this to be a
+     valid 'object.component' syntax.  */
+  if (getter || setter)
+    {
+      /* Yes ... determine the type of the expression.  */
+      tree property_decl;
+      tree type;
+      
+      if (getter)
+       type = TREE_VALUE (TREE_TYPE (getter));
+      else
+       type = TREE_VALUE (TREE_TYPE (METHOD_SEL_ARGS (setter)));
+      
+      /* Create an artificial property declaration with the
+        information we collected on the type and getter/setter
+        names.  */
+      property_decl = make_node (PROPERTY_DECL);
+      
+      TREE_TYPE (property_decl) = type;
+      DECL_SOURCE_LOCATION (property_decl) = input_location;
+      TREE_DEPRECATED (property_decl) = 0;
+      DECL_ARTIFICIAL (property_decl) = 1;
+             
+      /* Add property-specific information.  Note that one of
+        PROPERTY_GETTER_NAME or PROPERTY_SETTER_NAME may refer to a
+        non-existing method; this will generate an error when the
+        expression is later compiled.  At this stage we don't know if
+        the getter or setter will be used, so we can't generate an
+        error.  */
+      PROPERTY_NAME (property_decl) = component;
+      PROPERTY_GETTER_NAME (property_decl) = getter_name;
+      PROPERTY_SETTER_NAME (property_decl) = setter_name;
+      PROPERTY_READONLY (property_decl) = 0;
+      PROPERTY_NONATOMIC (property_decl) = 0;
+      PROPERTY_ASSIGN_SEMANTICS (property_decl) = 0;
+      PROPERTY_IVAR_NAME (property_decl) = NULL_TREE;
+      PROPERTY_DYNAMIC (property_decl) = 0;
+
+      if (!getter)
+       PROPERTY_HAS_NO_GETTER (property_decl) = 1;
+
+      /* The following is currently unused, but it's nice to have
+        there.  We may use it if we need in the future.  */
+      if (!setter)
+       PROPERTY_HAS_NO_SETTER (property_decl) = 1;
+
+      return property_decl;
+    }
+
+  return NULL_TREE;
+}
 
 /* This hook routine is invoked by the parser when an expression such
    as 'xxx.yyy' is parsed.  We get a chance to process these
    expressions in a way that is specified to Objective-C (to implement
-   properties, or non-fragile ivars).  If the expression is not an
-   Objective-C specified expression, we should return NULL_TREE; else
-   we return the expression.
-
-   At the moment this only implements properties (not non-fragile
-   ivars yet), ie 'object.property'.  */
+   the Objective-C 2.0 dot-syntax, properties, or non-fragile ivars).
+   If the expression is not an Objective-C specified expression, we
+   should return NULL_TREE; else we return the expression.
+
+   At the moment this only implements dot-syntax and properties (not
+   non-fragile ivars yet), ie 'object.property' or 'object.component'
+   where 'component' is not a declared property, but a valid getter or
+   setter for it could be found.  */
 tree
 objc_maybe_build_component_ref (tree object, tree property_ident)
 {
@@ -1089,6 +1175,17 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
                      : NULL_TREE);
       if (rprotos)
        x = lookup_property_in_protocol_list (rprotos, property_ident);
+
+      if (x == NULL_TREE)
+       {
+         /* Ok, no property.  Maybe it was an object.component
+            dot-syntax without a declared property.  Look for
+            getter/setter methods and internally declare an artifical
+            property based on them if found.  */
+         x = maybe_make_artificial_property_decl (NULL_TREE, rprotos, 
+                                                  property_ident,
+                                                  false);
+       }
     }
   else
     {
@@ -1115,6 +1212,14 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
 
          if (x == NULL_TREE)
            x = lookup_property_in_protocol_list (protocol_list, property_ident);
+
+         if (x == NULL_TREE)
+           {
+             /* Ok, no property.  Try the dot-syntax without a
+                declared property.  */
+             x = maybe_make_artificial_property_decl (interface_type, protocol_list, 
+                                                      property_ident, false);
+           }
        }
     }
 
@@ -1144,10 +1249,16 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
 
         TODO: This can be made more efficient; in particular we don't
         need to build the whole message call, we could just work on
-        the selector.  */
-      objc_finish_message_expr (object,
-                               PROPERTY_GETTER_NAME (x),
-                               NULL_TREE);
+        the selector.
+
+        If the PROPERTY_HAS_NO_GETTER() (ie, it is an artificial
+        property decl created to deal with a dotsyntax not really
+        referring to an existing property) then do not try to build a
+        call to the getter as there is no getter.  */
+      if (!PROPERTY_HAS_NO_GETTER (x))
+       objc_finish_message_expr (object,
+                                 PROPERTY_GETTER_NAME (x),
+                                 NULL_TREE);
       
       return expression;
     }
@@ -1197,6 +1308,9 @@ objc_maybe_build_modify_expr (tree lhs, tree rhs)
        {
          tree setter_argument = build_tree_list (NULL_TREE, rhs);
          tree setter;
+
+         /* TODO: Check that the setter return type is 'void'.  */
+
          /* TODO: Decay argument in C.  */
          setter = objc_finish_message_expr (object_expr, 
                                             PROPERTY_SETTER_NAME (property_decl),
index 4c10c01378e2c8e997bc3b1edaa403d7904b2acd..9478d72fbccf1a5f9603bf1dc7630ae25344ca4c 100644 (file)
@@ -62,6 +62,11 @@ tree objc_eh_personality (void);
 
 /* TREE_TYPE is the type (int, float, etc) of the property.  */
 
+/* DECL_ARTIFICIAL is set to 1 if the PROPERTY_DECL is an artificial
+   property declaration created when the dot-syntax object.component
+   is used with no actual @property matching the component, but a
+   valid getter/setter.  */
+
 /* PROPERTY_NAME is the name of the property.  */
 #define PROPERTY_NAME(DECL) DECL_NAME(DECL)
 
@@ -99,9 +104,21 @@ typedef enum objc_property_assign_semantics {
    declaration has been parsed); otherwise, it is set to 0.  */
 #define PROPERTY_DYNAMIC(DECL) DECL_LANG_FLAG_2 (DECL)
 
+/* PROPERTY_HAS_NO_GETTER can be 0 or 1.  Normally it is 0, but if
+   this is an artificial PROPERTY_DECL that we generate even without a
+   getter, it is set to 1.  */
+#define PROPERTY_HAS_NO_GETTER(DECL) DECL_LANG_FLAG_3 (DECL)
+
+/* PROPERTY_HAS_NO_SETTER can be 0 or 1.  Normally it is 0, but if
+   this is an artificial PROPERTY_DECL that we generate even without a
+   setter, it is set to 1.  */
+#define PROPERTY_HAS_NO_SETTER(DECL) DECL_LANG_FLAG_4 (DECL)
 
 /* PROPERTY_REF.  A PROPERTY_REF represents an 'object.property'
-   expression.  */
+   expression.  It is normally used for property access, but when
+   the Objective-C 2.0 "dot-syntax" (object.component) is used
+   with no matching property, a PROPERTY_REF is still created to
+   represent it, with an artificial PROPERTY_DECL.  */
 
 /* PROPERTY_REF_OBJECT is the object whose property we are
    accessing.  */
@@ -109,7 +126,9 @@ typedef enum objc_property_assign_semantics {
 
 /* PROPERTY_REF_PROPERTY_DECL is the PROPERTY_DECL for the property
    used in the expression.  From it, you can get the property type,
-   and the getter/setter names.  */
+   and the getter/setter names.  This PROPERTY_DECL could be artificial
+   if we are processing an 'object.component' syntax with no matching 
+   declared property.  */
 #define PROPERTY_REF_PROPERTY_DECL(NODE) TREE_OPERAND (PROPERTY_REF_CHECK (NODE), 1)
 
 
index 5da2671c79e8ee540add481d152c7402fee9d530..7316675c3bd1675802b60a0328d0fc2f88aa54d5 100644 (file)
@@ -55,7 +55,11 @@ DEFTREECODE (CLASS_REFERENCE_EXPR, "class_reference_expr", tcc_expression, 1)
     * else, it will remain as a PROPERTY_REF until we get to
       gimplification; at that point, we convert each PROPERTY_REF into
       a 'getter' call during ObjC/ObjC++ gimplify.
-*/
+
+  Please note that when the Objective-C 2.0 "dot-syntax" 'object.component' 
+  is encountered, where 'component' is not a property but there are valid
+  setter/getter methods for it, an artificial PROPERTY_DECL is generated
+  and used in the PROPERTY_REF.  */
 DEFTREECODE (PROPERTY_REF, "property_ref", tcc_expression, 2)
 
 /*
index d97167acda6b4efbdecf72a3080b85a2ebc38c7b..a8851e499a0dcf5b6681be5582d3cdae3693a38c 100644 (file)
@@ -1,3 +1,10 @@
+2010-11-03  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       * objc.dg/property/dotsyntax-1.m: New.
+       * objc.dg/property/dotsyntax-2.m: New.  
+       * obj-c++.dg/property/dotsyntax-1.mm: New.
+       * obj-c++.dg/property/dotsyntax-2.mm: New.      
+
 2010-11-03  Jakub Jelinek  <jakub@redhat.com>
 
        PR tree-optimization/46165
diff --git a/gcc/testsuite/obj-c++.dg/property/dotsyntax-1.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-1.mm
new file mode 100644 (file)
index 0000000..8bc3b3a
--- /dev/null
@@ -0,0 +1,62 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do run } */
+
+/* Test the 'dot syntax' without a declarated property.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+  int a;
+  id b;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+- (int) count;
+- (void) setCount: (int)value;
+- (id) next;
+- (void) setNext: (id)value;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+- (int) count
+{
+  return a;
+}
+- (void) setCount: (int)value
+{
+  a = value;
+}
+- (id) next
+{
+  return b;
+}
+- (void) setNext: (id)value
+{
+  b = value;
+}
+@end
+
+int main (void)
+{
+  MyRootClass *object = [[MyRootClass alloc] init];
+
+  object.count = 40;
+  if (object.count != 40)
+    abort ();
+
+  object.next = object;
+  if (object.next != object)
+    abort ();
+
+  return 0;
+}
+
+
diff --git a/gcc/testsuite/obj-c++.dg/property/dotsyntax-2.mm b/gcc/testsuite/obj-c++.dg/property/dotsyntax-2.mm
new file mode 100644 (file)
index 0000000..ba615a3
--- /dev/null
@@ -0,0 +1,71 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do run } */
+
+/* Test the 'dot syntax' without a declarated property.  This tests the case where
+   only the setter (or only the getter) exists.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+  int a;
+  id b;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+- (int) a;
+- (void) setCount: (int)value;
+- (id) b;
+- (void) setNext: (id)value;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+- (int) a
+{
+  return a;
+}
+- (void) setCount: (int)value
+{
+  a = value;
+}
+- (id) b
+{
+  return b;
+}
+- (void) setNext: (id)value
+{
+  b = value;
+}
+@end
+
+int main (void)
+{
+  MyRootClass *object = [[MyRootClass alloc] init];
+
+  /* This should work because -setCount: exists (even if -count does
+     not).  */
+  object.count = 40;
+
+  /* This should work because -a exists (even if -setA: does not).  */
+  if (object.a != 40)
+    abort ();
+
+  /* This should work because -setNext: exists (even if -next does
+     not).  */
+  object.next = object;
+
+  /* This should work because -b exists (even if -setB: does not).  */
+  if (object.b != object)
+    abort ();
+
+  return 0;
+}
+
+
diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-1.m b/gcc/testsuite/objc.dg/property/dotsyntax-1.m
new file mode 100644 (file)
index 0000000..8bc3b3a
--- /dev/null
@@ -0,0 +1,62 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do run } */
+
+/* Test the 'dot syntax' without a declarated property.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+  int a;
+  id b;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+- (int) count;
+- (void) setCount: (int)value;
+- (id) next;
+- (void) setNext: (id)value;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+- (int) count
+{
+  return a;
+}
+- (void) setCount: (int)value
+{
+  a = value;
+}
+- (id) next
+{
+  return b;
+}
+- (void) setNext: (id)value
+{
+  b = value;
+}
+@end
+
+int main (void)
+{
+  MyRootClass *object = [[MyRootClass alloc] init];
+
+  object.count = 40;
+  if (object.count != 40)
+    abort ();
+
+  object.next = object;
+  if (object.next != object)
+    abort ();
+
+  return 0;
+}
+
+
diff --git a/gcc/testsuite/objc.dg/property/dotsyntax-2.m b/gcc/testsuite/objc.dg/property/dotsyntax-2.m
new file mode 100644 (file)
index 0000000..ba615a3
--- /dev/null
@@ -0,0 +1,71 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, November 2010.  */
+/* { dg-do run } */
+
+/* Test the 'dot syntax' without a declarated property.  This tests the case where
+   only the setter (or only the getter) exists.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+  int a;
+  id b;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+- (int) a;
+- (void) setCount: (int)value;
+- (id) b;
+- (void) setNext: (id)value;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+- (int) a
+{
+  return a;
+}
+- (void) setCount: (int)value
+{
+  a = value;
+}
+- (id) b
+{
+  return b;
+}
+- (void) setNext: (id)value
+{
+  b = value;
+}
+@end
+
+int main (void)
+{
+  MyRootClass *object = [[MyRootClass alloc] init];
+
+  /* This should work because -setCount: exists (even if -count does
+     not).  */
+  object.count = 40;
+
+  /* This should work because -a exists (even if -setA: does not).  */
+  if (object.a != 40)
+    abort ();
+
+  /* This should work because -setNext: exists (even if -next does
+     not).  */
+  object.next = object;
+
+  /* This should work because -b exists (even if -setB: does not).  */
+  if (object.b != object)
+    abort ();
+
+  return 0;
+}
+
+