]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
NS/CF String format syntax parsing.
authorIain Sandoe <iains@gcc.gnu.org>
Sat, 6 Nov 2010 10:48:18 +0000 (10:48 +0000)
committerIain Sandoe <iains@gcc.gnu.org>
Sat, 6 Nov 2010 10:48:18 +0000 (10:48 +0000)
gcc:

PR target/44981
* doc/extend.tex (format): Document NSString extension.
(format_arg): Likewise.
(Darwin Format Checks): New section.
* doc/tm.texi: Document string object hooks (generated).
* doc/tm.texi.in (TARGET_OBJC_CONSTRUCT_STRING_OBJECT) Rename.
(TARGET_STRING_OBJECT_REF_TYPE_P): New.
(TARGET_CHECK_STRING_OBJECT_FORMAT_ARG): New.
* target.def (objc_construct_string_object): Rename, amend
documentation.
(string_object_ref_type_p): New hook.
(check_string_object_format_arg): New hook.
* c-parser.c (c_parser_attributes): Allow objective-c class names as
attribute identifiers.
* config/darwin-c.c (darwin_cfstring_ref_p): New.
(darwin_check_cfstring_format_arg): New.
(darwin_additional_format_types): New.
* config/darwin-protos.h (darwin_cfstring_ref_p) New.
(darwin_check_cfstring_format_arg): New.
* config/darwin.h (TARGET_OBJC_CONSTRUCT_STRING_OBJECT) Renamed.
(TARGET_STRING_OBJECT_REF_TYPE_P): New.
(TARGET_N_FORMAT_TYPES): New.
(TARGET_CHECK_STRING_OBJECT_FORMAT_ARG): New.

gcc/c-family:

PR target/44981
* c-format.c (format_type): New type gcc_objc_string_format_type.
(valid_stringptr_type_p): New.
(handle_format_arg_attribute): Use valid_stringptr_type_p ().
(check_format_string): Pass expected type, use
valid_stringptr_type_p (), check that the format string types are
consistent with the format specification.
(decode_format_attr): Warn if NSString is used outside objective-c.
(format_types_orig): Add NSString.
(format_name): New.
(format_flags): New.
(check_format_arg): Handle format strings requiring an external parser.
first_target_format_type: New variable.
(handle_format_attribute): Set up first_target_format_type, pass the
expected format arg string type to check_format_string().
* c-common.h (FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL):  New flag.
* stub-objc.c (objc_string_ref_type_p): New.
(objc_check_format_arg): New.

gcc/objc:

PR target/44981
* objc-act.c (objc_build_string_object): Amend for renamed hook.
(objc_string_ref_type_p): New.
(objc_check_format_arg): New.

gcc/testsuite:

PR target/44981
* gcc.dg/darwin-cfstring-format-1.c: New.
* gcc.dg/warn-nsstring.c: New.
* objc.dg/fsf-nsstring-format-1.m: New.
* obj-c++.dg/fsf-nsstring-format-1.mm: New.
* obj-c++.dg/torture/strings/const-cfstring-1.mm: Update for darwin10
linker warning.

From-SVN: r166398

23 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-common.h
gcc/c-family/c-format.c
gcc/c-family/c-format.h
gcc/c-family/stub-objc.c
gcc/c-parser.c
gcc/config/darwin-c.c
gcc/config/darwin-protos.h
gcc/config/darwin.h
gcc/doc/extend.texi
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/objc/ChangeLog
gcc/objc/objc-act.c
gcc/target.def
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/darwin-cfstring-format-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/warn-nsstring.c [new file with mode: 0644]
gcc/testsuite/lib/gcc-defs.exp
gcc/testsuite/obj-c++.dg/fsf-nsstring-format-1.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/torture/strings/const-cfstring-1.mm
gcc/testsuite/objc.dg/fsf-nsstring-format-1.m [new file with mode: 0644]

index 98be40aba0ab2ec6ef070ebbbdc7c4238fb350c6..e3f26e8969bb0f9ada648a29ed2f060c709da774 100644 (file)
@@ -1,3 +1,29 @@
+2010-11-06  Iain Sandoe  <iains@gcc.gnu.org>
+
+       PR target/44981
+       * doc/extend.tex (format): Document NSString extension.
+       (format_arg): Likewise.
+       (Darwin Format Checks): New section.
+       * doc/tm.texi: Document string object hooks (generated).
+       * doc/tm.texi.in (TARGET_OBJC_CONSTRUCT_STRING_OBJECT) Rename.
+       (TARGET_STRING_OBJECT_REF_TYPE_P): New.
+       (TARGET_CHECK_STRING_OBJECT_FORMAT_ARG): New.
+       * target.def (objc_construct_string_object): Rename, amend 
+       documentation.
+       (string_object_ref_type_p): New hook.
+       (check_string_object_format_arg): New hook.
+       * c-parser.c (c_parser_attributes): Allow objective-c class names as
+       attribute identifiers.
+       * config/darwin-c.c (darwin_cfstring_ref_p): New.
+       (darwin_check_cfstring_format_arg): New.
+       (darwin_additional_format_types): New.
+       * config/darwin-protos.h (darwin_cfstring_ref_p) New.
+       (darwin_check_cfstring_format_arg): New.
+       * config/darwin.h (TARGET_OBJC_CONSTRUCT_STRING_OBJECT) Renamed.
+       (TARGET_STRING_OBJECT_REF_TYPE_P): New.
+       (TARGET_N_FORMAT_TYPES): New.
+       (TARGET_CHECK_STRING_OBJECT_FORMAT_ARG): New.
+
 2010-11-06  Eric Botcazou  <ebotcazou@adacore.com>
             Pascal Obry  <obry@adacore.com>
 
index c613ab36b8b484ce9286661ef84ed1a4f2999e1b..1164d919d0eb249c2e79f4ba1073db6035a689da 100644 (file)
@@ -1,3 +1,24 @@
+2010-11-06  Iain Sandoe  <iains@gcc.gnu.org>
+
+       PR target/44981
+       * c-format.c (format_type): New type gcc_objc_string_format_type.
+       (valid_stringptr_type_p): New.
+       (handle_format_arg_attribute): Use valid_stringptr_type_p ().
+       (check_format_string): Pass expected type, use 
+       valid_stringptr_type_p (), check that the format string types are
+       consistent with the format specification.
+       (decode_format_attr): Warn if NSString is used outside objective-c.
+       (format_types_orig): Add NSString.
+       (format_name): New.
+       (format_flags): New.
+       (check_format_arg): Handle format strings requiring an external parser.
+       first_target_format_type: New variable.
+       (handle_format_attribute): Set up first_target_format_type, pass the
+       expected format arg string type to check_format_string().
+       * c-common.h (FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL):  New flag.
+       * stub-objc.c (objc_string_ref_type_p): New.
+       (objc_check_format_arg): New.
+
 2010-11-04  Nicola Pero  <nicola.pero@meta-innovation.com>
 
        Fixed using the Objective-C 2.0 dot-syntax with class names.    
index 13d9227ddca8580055487ece619df992b00c099a..58d3a321e0f6bab82510c7d3b62fdfb256a3846b 100644 (file)
@@ -1043,6 +1043,8 @@ extern void objc_add_synthesize_declaration (location_t, tree);
 extern void objc_add_dynamic_declaration (location_t, tree);
 extern const char * objc_maybe_printable_name (tree, int);
 extern bool objc_is_property_ref (tree);
+extern bool objc_string_ref_type_p (tree);
+extern void objc_check_format_arg (tree, tree);
 
 /* The following are provided by the C and C++ front-ends, and called by
    ObjC/ObjC++.  */
index e7fd2295d52903b1cdb40b92acd433f6e505294d..a64717a5510040fac8f492e6378d0fdbcc43211a 100644 (file)
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "c-format.h"
 #include "alloc-pool.h"
+#include "target.h"
 \f
 /* Set format warning options according to a -Wformat=n option.  */
 
@@ -63,6 +64,7 @@ enum format_type { printf_format_type, asm_fprintf_format_type,
                   gcc_diag_format_type, gcc_tdiag_format_type,
                   gcc_cdiag_format_type,
                   gcc_cxxdiag_format_type, gcc_gfc_format_type,
+                  gcc_objc_string_format_type,
                   format_type_error = -1};
 
 typedef struct function_format_info
@@ -77,12 +79,38 @@ static int decode_format_type (const char *);
 
 static bool check_format_string (tree argument,
                                 unsigned HOST_WIDE_INT format_num,
-                                int flags, bool *no_add_attrs);
+                                int flags, bool *no_add_attrs,
+                                int expected_format_type);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
                          int validated_p);
 static const char *convert_format_name_to_system_name (const char *attr_name);
 static bool cmp_attribs (const char *tattr_name, const char *attr_name);
 
+static int first_target_format_type;
+static const char *format_name (int format_num);
+static int format_flags (int format_num);
+
+/* Check that we have a pointer to a string suitable for use as a format.
+   The default is to check for a char type.
+   For objective-c dialects, this is extended to include references to string
+   objects validated by objc_string_ref_type_p ().  
+   Targets may also provide a string object type that can be used within c and 
+   c++ and shared with their respective objective-c dialects. In this case the
+   reference to a format string is checked for validity via a hook.
+   
+   The function returns true if strref points to any string type valid for the 
+   language dialect and target.  */
+
+static bool
+valid_stringptr_type_p (tree strref)
+{
+  return (strref != NULL
+         && TREE_CODE (strref) == POINTER_TYPE
+         && (TYPE_MAIN_VARIANT (TREE_TYPE (strref)) == char_type_node
+             || objc_string_ref_type_p (strref)
+             || (*targetcm.string_object_ref_type_p) ((const_tree) strref)));
+}
+
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
@@ -104,13 +132,13 @@ handle_format_arg_attribute (tree *node, tree ARG_UNUSED (name),
   argument = TYPE_ARG_TYPES (type);
   if (argument)
     {
-      if (!check_format_string (argument, format_num, flags, no_add_attrs))
+      /* The format arg can be any string reference valid for the language and
+         target.  We cannot be more specific in this case.  */
+      if (!check_format_string (argument, format_num, flags, no_add_attrs, -1))
        return NULL_TREE;
     }
 
-  if (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
-      || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
-         != char_type_node))
+  if (!valid_stringptr_type_p (TREE_TYPE (type)))
     {
       if (!(flags & (int) ATTR_FLAG_BUILT_IN))
        error ("function does not return string type");
@@ -121,13 +149,18 @@ handle_format_arg_attribute (tree *node, tree ARG_UNUSED (name),
   return NULL_TREE;
 }
 
-/* Verify that the format_num argument is actually a string, in case
-   the format attribute is in error.  */
+/* Verify that the format_num argument is actually a string reference suitable,
+   for the language dialect and target (in case the format attribute is in 
+   error).  When we know the specific reference type expected, this is also 
+   checked.  */
 static bool
 check_format_string (tree argument, unsigned HOST_WIDE_INT format_num,
-                    int flags, bool *no_add_attrs)
+                    int flags, bool *no_add_attrs, int expected_format_type)
 {
   unsigned HOST_WIDE_INT i;
+  bool is_objc_sref, is_target_sref, is_char_ref;
+  tree ref;
+  int fmt_flags;
 
   for (i = 1; i != format_num; i++)
     {
@@ -137,17 +170,78 @@ check_format_string (tree argument, unsigned HOST_WIDE_INT format_num,
     }
 
   if (!argument
-      || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE
-      || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
-         != char_type_node))
+      || !(ref = TREE_VALUE (argument))
+      || !valid_stringptr_type_p (ref))
     {
       if (!(flags & (int) ATTR_FLAG_BUILT_IN))
-       error ("format string argument not a string type");
+       error ("format string argument is not a string type");
       *no_add_attrs = true;
       return false;
     }
 
-  return true;
+  /* We only know that we want a suitable string reference.  */
+  if (expected_format_type < 0)
+    return true;
+
+  /* Now check that the arg matches the expected type.  */
+  is_char_ref = 
+    (TYPE_MAIN_VARIANT (TREE_TYPE (ref)) == char_type_node);
+
+  fmt_flags = format_flags (expected_format_type);
+  is_objc_sref = is_target_sref = false;
+  if (!is_char_ref)
+    is_objc_sref = objc_string_ref_type_p (ref);
+
+  if (!(fmt_flags & FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL))
+    {
+      if (is_char_ref)
+       return true; /* OK, we expected a char and found one.  */
+      else
+       {
+         /* We expected a char but found an extended string type.  */
+         if (is_objc_sref)
+           error ("found a %<%s%> reference but the format argument should"
+                  " be a string", format_name (gcc_objc_string_format_type));
+         else
+           error ("found a %qT but the format argument should be a string",
+                  ref);
+         *no_add_attrs = true;
+         return false;
+       }
+    }
+
+  /* We expect a string object type as the format arg.  */
+  if (is_char_ref)
+    {
+      error ("format argument should be a %<%s%> reference but"
+            " a string was found", format_name (expected_format_type));
+      *no_add_attrs = true;
+      return false;
+    }
+  
+  /* We will assert that objective-c will support either its own string type
+     or the target-supplied variant.  */
+  if (!is_objc_sref)
+    is_target_sref = (*targetcm.string_object_ref_type_p) ((const_tree) ref);
+
+  if (expected_format_type == (int) gcc_objc_string_format_type 
+      && (is_objc_sref || is_target_sref))
+    return true;
+
+  /* We will allow a target string ref to match only itself.  */
+  if (first_target_format_type 
+      && expected_format_type >= first_target_format_type
+      && is_target_sref)
+    return true;
+  else
+    {
+      error ("format argument should be a %<%s%> reference", 
+             format_name (expected_format_type));
+      *no_add_attrs = true;
+      return false;
+    }
+
+  gcc_unreachable ();
 }
 
 /* Verify EXPR is a constant, and store its value.
@@ -195,6 +289,16 @@ decode_format_attr (tree args, function_format_info *info, int validated_p)
       p = convert_format_name_to_system_name (p);
 
       info->format_type = decode_format_type (p);
+      
+      if (!c_dialect_objc ()
+          && info->format_type == gcc_objc_string_format_type)
+       {
+         gcc_assert (!validated_p);
+         warning (OPT_Wformat, "%qE is only allowed in Objective-C dialects",
+                  format_type_id);
+         info->format_type = format_type_error;
+         return false;
+       }
 
       if (info->format_type == format_type_error)
        {
@@ -750,6 +854,11 @@ static const format_kind_info format_types_orig[] =
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
+  { "NSString",   NULL,  NULL, NULL, NULL,
+    NULL, NULL,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL, 0, 0, 0, 0, 0, 0,
+    NULL, NULL
+  },
   { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
@@ -812,6 +921,26 @@ typedef struct
   tree params;
 } format_check_context;
 
+/* Return the format name (as specified in the original table) for the format
+   type indicated by format_num.  */
+static const char *
+format_name (int format_num)
+{
+  if (format_num >= 0 && format_num < n_format_types)
+    return format_types[format_num].name;
+  gcc_unreachable ();
+}
+
+/* Return the format flags (as specified in the original table) for the format
+   type indicated by format_num.  */
+static int
+format_flags (int format_num)
+{
+  if (format_num >= 0 && format_num < n_format_types)
+    return format_types[format_num].flags;
+  gcc_unreachable ();
+}
+
 static void check_format_info (function_format_info *, tree);
 static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT);
 static void check_format_info_main (format_check_results *,
@@ -1349,6 +1478,39 @@ check_format_arg (void *ctx, tree format_tree,
       return;
     }
   format_tree = TREE_OPERAND (format_tree, 0);
+  if (format_types[info->format_type].flags 
+      & (int) FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL)
+    {
+      bool objc_str = (info->format_type == gcc_objc_string_format_type);
+      /* We cannot examine this string here - but we can check that it is
+         a valid type.  */
+      if (TREE_CODE (format_tree) != CONST_DECL
+         || !((objc_str && objc_string_ref_type_p (TREE_TYPE (format_tree)))
+               || (*targetcm.string_object_ref_type_p) 
+                                    ((const_tree) TREE_TYPE (format_tree))))
+       {
+         res->number_non_literal++;
+         return;
+       }
+      /* Skip to first argument to check.  */
+      while (arg_num + 1 < info->first_arg_num)
+       {
+         if (params == 0)
+           return;
+         params = TREE_CHAIN (params);
+         ++arg_num;
+       }
+      /* So, we have a valid literal string object and one or more params.
+         We need to use an external helper to parse the string into format
+         info.  For Objective-C variants we provide the resource within the
+         objc tree, for target variants, via a hook.  */
+      if (objc_str)
+       objc_check_format_arg (format_tree, params);
+      else if (targetcm.check_string_object_format_arg)
+       (*targetcm.check_string_object_format_arg) (format_tree, params);
+      /* Else we can't handle it and retire quietly.  */
+      return;
+    }
   if (TREE_CODE (format_tree) == ARRAY_REF
       && host_integerp (TREE_OPERAND (format_tree, 1), 0)
       && (offset += tree_low_cst (TREE_OPERAND (format_tree, 1), 0)) >= 0)
@@ -2785,6 +2947,8 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
              TARGET_N_FORMAT_TYPES * sizeof (dynamic_format_types[0]));
 
       format_types = dynamic_format_types;
+      /* Provide a reference for the first potential external type.  */
+      first_target_format_type = n_format_types;
       n_format_types += TARGET_N_FORMAT_TYPES;
     }
 #endif
@@ -2799,7 +2963,7 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
   if (argument)
     {
       if (!check_format_string (argument, info.format_num, flags,
-                               no_add_attrs))
+                               no_add_attrs, info.format_type))
        return NULL_TREE;
 
       if (info.first_arg_num != 0)
index 9d01f0af495456caceb20c79323fa9bb3a4d1f6e..286219b16df9b3f81de356fa2e012445a5d89785 100644 (file)
@@ -1,6 +1,6 @@
 /* Check calls to formatted I/O functions (-Wformat).
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
+   2001, 2002, 2003, 2004, 2007, 2008, 2010 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -73,7 +73,10 @@ enum
   FMT_FLAG_EMPTY_PREC_OK = 64,
   /* Gaps are allowed in the arguments with $ operand numbers if all
      arguments are pointers (scanf).  */
-  FMT_FLAG_DOLLAR_GAP_POINTER_OK = 128
+  FMT_FLAG_DOLLAR_GAP_POINTER_OK = 128,
+  /* The format arg is an opaque object that will be parsed by an external
+     facility.  */
+  FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL = 256
   /* Not included here: details of whether width or precision may occur
      (controlled by width_char and precision_char); details of whether
      '*' can be used for these (width_type and precision_type); details
index 1f3b854f0c070dd2933cb7886e17767875e6451e..9dd6ef52f89a63c5b4c1fae985682bce8f3a2e6c 100644 (file)
@@ -2,7 +2,7 @@
    that are called from within the C and C++ front-ends,
    respectively.
    Copyright (C) 1991, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+   2004, 2005, 2007, 2009, 2010 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -440,3 +440,15 @@ void
 objc_write_global_declarations (void)
 {
 }
+
+bool
+objc_string_ref_type_p (tree ARG_UNUSED (strp))
+{
+   return false;
+}
+
+void
+objc_check_format_arg (tree ARG_UNUSED (format_arg), 
+                      tree ARG_UNUSED (args_list))
+{
+}
index 78ccdd4ebfc24b19ee0cf5185c77dab5fb859faa..e7403b2b182129a4afe73e0548292c089df83ac8 100644 (file)
@@ -3278,9 +3278,12 @@ c_parser_attributes (c_parser *parser)
          /* Parse the attribute contents.  If they start with an
             identifier which is followed by a comma or close
             parenthesis, then the arguments start with that
-            identifier; otherwise they are an expression list.  */
+            identifier; otherwise they are an expression list.  
+            In objective-c the identifier may be a classname.  */
          if (c_parser_next_token_is (parser, CPP_NAME)
-             && c_parser_peek_token (parser)->id_kind == C_ID_ID
+             && (c_parser_peek_token (parser)->id_kind == C_ID_ID
+                 || (c_dialect_objc () 
+                     && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
              && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
                  || (c_parser_peek_2nd_token (parser)->type
                      == CPP_CLOSE_PAREN)))
index ef3cfbc56b50e091acc0ce7650beb755a8828c50..99b6db1637d38aa6f17cd3e7daee24451db68d22 100644 (file)
@@ -1,5 +1,5 @@
 /* Darwin support needed only by C/C++ frontends.
-   Copyright (C) 2001, 2003, 2004, 2005, 2007, 2008
+   Copyright (C) 2001, 2003, 2004, 2005, 2007, 2008, 2010
    Free Software Foundation, Inc.
    Contributed by Apple Computer Inc.
 
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "incpath.h"
 #include "c-family/c-common.h"
 #include "c-family/c-pragma.h"
+#include "c-family/c-format.h"
 #include "diagnostic-core.h"
 #include "toplev.h"
 #include "flags.h"
@@ -678,3 +679,37 @@ darwin_objc_construct_string (tree str)
 
   return darwin_build_constant_cfstring (str);
 }
+
+/* The string ref type is created as CFStringRef by <CFBase.h> therefore, we
+   must match for it explicitly, since it's outside the gcc code.  */
+
+bool
+darwin_cfstring_ref_p (const_tree strp)
+{
+  tree tn;
+  if (!strp || TREE_CODE (strp) != POINTER_TYPE)
+    return false;
+
+  tn = TYPE_NAME (strp);
+  if (tn) 
+    tn = DECL_NAME (tn);
+  return (tn 
+         && IDENTIFIER_POINTER (tn)
+         && !strncmp (IDENTIFIER_POINTER (tn), "CFStringRef", 8));
+}
+
+/* At present the behavior of this is undefined and it does nothing.  */
+void
+darwin_check_cfstring_format_arg (tree ARG_UNUSED (format_arg), 
+                                 tree ARG_UNUSED (args_list))
+{
+}
+
+/* The extra format types we recognize.  */
+const format_kind_info darwin_additional_format_types[] = {
+  { "CFString",   NULL,  NULL, NULL, NULL, 
+    NULL, NULL, 
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL, 0, 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
index 30b3f822c98978facb991d5b8c664358ef13b235..e70de1bee80433b24b04a839c36fd4c7881640f8 100644 (file)
@@ -97,7 +97,9 @@ extern void darwin_init_cfstring_builtins (unsigned);
 extern tree darwin_fold_builtin (tree, int, tree *, bool);
 extern tree darwin_objc_construct_string (tree);
 extern bool darwin_cfstring_p (tree);
-extern tree darwin_build_constant_cfstring (tree str);
+extern bool darwin_cfstring_ref_p (const_tree);
+extern void darwin_check_cfstring_format_arg (tree, tree);
+extern tree darwin_build_constant_cfstring (tree);
 extern void darwin_enter_string_into_cfstring_table (tree);
 
 extern void darwin_asm_output_anchor (rtx symbol);
index 1974704d25ab43838ccb33b545ad8e24578de0af..ffed58a1300ef4d3a54ecf1130b081706614c60f 100644 (file)
@@ -1023,9 +1023,18 @@ __enable_execute_stack (void *addr)                                     \
 /* We have target-specific builtins.  */
 #define TARGET_FOLD_BUILTIN darwin_fold_builtin
 
-#define TARGET_OBJC_CONSTRUCT_STRING \
+#define TARGET_OBJC_CONSTRUCT_STRING_OBJECT \
   darwin_objc_construct_string
 
+#define TARGET_STRING_OBJECT_REF_TYPE_P \
+  darwin_cfstring_ref_p
+
+#define TARGET_N_FORMAT_TYPES 1
+#define TARGET_FORMAT_TYPES darwin_additional_format_types
+
+#define TARGET_CHECK_STRING_OBJECT_FORMAT_ARG \
+  darwin_check_cfstring_format_arg
+
 #define TARGET_HAS_TARGETCM 1
 
 #ifndef CROSS_DIRECTORY_STRUCTURE
index 95e9d8808f8e05a8b96b1824bc9918c768ffdb1b..577c35a15adc107dbe25c3c77e828f897c574cac 100644 (file)
@@ -2418,7 +2418,13 @@ standard modes, the X/Open function @code{strfmon} is also checked as
 are @code{printf_unlocked} and @code{fprintf_unlocked}.
 @xref{C Dialect Options,,Options Controlling C Dialect}.
 
-The target may provide additional types of format checks.
+For Objective-C dialects, @code{NSString} (or @code{__NSString__}) is 
+recognized in the same context.  Declarations including these format attributes
+will be parsed for correct syntax, however the result of checking of such format
+strings is not yet defined, and will not be carried out by this version of the 
+compiler.
+
+The target may also provide additional types of format checks.
 @xref{Target Format Checks,,Format Checks Specific to Particular
 Target Machines}.
 
@@ -2467,6 +2473,14 @@ requested by @option{-ansi} or an appropriate @option{-std} option, or
 is used.  @xref{C Dialect Options,,Options
 Controlling C Dialect}.
 
+For Objective-C dialects, the @code{format-arg} attribute may refer to an
+@code{NSString} reference for compatibility with the @code{format} attribute
+above.
+
+The target may also allow additional types in @code{format-arg} attributes.
+@xref{Target Format Checks,,Format Checks Specific to Particular
+Target Machines}.
+
 @item function_vector
 @cindex calling functions through the function vector on H8/300, M16C, M32C and SH2A processors
 Use this attribute on the H8/300, H8/300H, and H8S to indicate that the specified
@@ -12426,6 +12440,7 @@ format attribute
 
 @menu
 * Solaris Format Checks::
+* Darwin Format Checks::
 @end menu
 
 @node Solaris Format Checks
@@ -12436,6 +12451,20 @@ check.  @code{cmn_err} accepts a subset of the standard @code{printf}
 conversions, and the two-argument @code{%b} conversion for displaying
 bit-fields.  See the Solaris man page for @code{cmn_err} for more information.
 
+@node Darwin Format Checks
+@subsection Darwin Format Checks
+
+Darwin targets support the @code{CFString} (or @code{__CFString__}) in the format 
+attribute context.  Declarations made with such attribution will be parsed for correct syntax
+and format argument types.  However, parsing of the format string itself is currently undefined
+and will not be carried out by this version of the compiler.  
+
+Additionally, @code{CFStringRefs} (defined by the @code{CoreFoundation} headers) may
+also be used as format arguments.  Note that the relevant headers are only likely to be
+available on Darwin (OSX) installations.  On such installations, the XCode and system
+documentation provide descriptions of @code{CFString}, @code{CFStringRefs} and
+associated functions.
+
 @node Pragmas
 @section Pragmas Accepted by GCC
 @cindex pragmas
index 0bb146e9cf24b16e9d406bf47c3dc94ea6596e07..7666fcfd401d5dd006b21ecce1d9a6af284f62c5 100644 (file)
@@ -715,8 +715,16 @@ only available in the C (and related language) front ends, then you
 should use @code{TARGET_HANDLE_C_OPTION} instead.
 @end deftypefn
 
-@deftypefn {Target Hook} tree TARGET_OBJC_CONSTRUCT_STRING (tree @var{string})
-Construct a constant string representation for @var{string}
+@deftypefn {Target Hook} tree TARGET_OBJC_CONSTRUCT_STRING_OBJECT (tree @var{string})
+Targets may provide a string object type that can be used within and between C, C++ and their respective Objective-C dialects. A string object might, for example, embed encoding and length information. These objects are considered opaque to the compiler and handled as references. An ideal implementation makes the composition of the string object match that of the Objective-C @code{NSString} (@code{NXString} for GNUStep), allowing efficient interworking between C-only and Objective-C code. If a target implements string objects then this hook should return a reference to such an object constructed from the normal `C' string representation provided in @var{string}. At present, the hook is used by Objective-C only, to obtain a common-format string object when the target provides one.
+@end deftypefn
+
+@deftypefn {Target Hook} bool TARGET_STRING_OBJECT_REF_TYPE_P (const_tree @var{stringref})
+If a target implements string objects then this hook should return @code{true} if @var{stringref} is a valid reference to such an object.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_CHECK_STRING_OBJECT_FORMAT_ARG (tree @var{format_arg}, tree @var{args_list})
+If a target implements string objects then this hook should should  provide a facility to check the function arguments in @var{args_list}  against the format specifiers in @var{format_arg} where the type of  @var{format_arg} is one recognized as a valid string reference type.
 @end deftypefn
 
 @defmac TARGET_VERSION
index 6bf51d65d24ba93037888f6ac23855473973d099..b0c4bccc70422aee35abfabb43c6ab8ff345d81f 100644 (file)
@@ -715,7 +715,11 @@ only available in the C (and related language) front ends, then you
 should use @code{TARGET_HANDLE_C_OPTION} instead.
 @end deftypefn
 
-@hook TARGET_OBJC_CONSTRUCT_STRING
+@hook TARGET_OBJC_CONSTRUCT_STRING_OBJECT
+
+@hook TARGET_STRING_OBJECT_REF_TYPE_P
+
+@hook TARGET_CHECK_STRING_OBJECT_FORMAT_ARG
 
 @defmac TARGET_VERSION
 This macro is a C statement to print on @code{stderr} a string
index dc4cffd1e53180ff255311530442fe7db80625a9..104948ba908b507b56f277472ee19b1aff660840 100644 (file)
@@ -1,3 +1,10 @@
+2010-11-06  Iain Sandoe  <iains@gcc.gnu.org>
+
+       PR target/44981
+       * objc-act.c (objc_build_string_object): Amend for renamed hook.
+       (objc_string_ref_type_p): New.
+       (objc_check_format_arg): New.
+
 2010-11-04  Nicola Pero  <nicola.pero@meta-innovation.com>
 
        Fixed using the Objective-C 2.0 dot-syntax with class names.    
index aa4c2e392b8545fc8984b59e9522c627953725c5..02966a89fdf1cce44fcd9b59c9a31f46829944f0 100644 (file)
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "c-family/c-common.h"
 #include "c-family/c-pragma.h"
+#include "c-family/c-format.h"
 #include "flags.h"
 #include "langhooks.h"
 #include "objc-act.h"
@@ -2755,9 +2756,9 @@ objc_build_string_object (tree string)
      literal.  On Darwin (Mac OS X), for example, we may wish to obtain a 
      constant CFString reference instead.
      At present, this is only supported for the NeXT runtime.  */
-  if (flag_next_runtime && targetcm.objc_construct_string)
+  if (flag_next_runtime && targetcm.objc_construct_string_object)
     {
-      tree constructor = (*targetcm.objc_construct_string) (string);
+      tree constructor = (*targetcm.objc_construct_string_object) (string);
       if (constructor)
        return build1 (NOP_EXPR, objc_object_type, constructor);
     }
@@ -12673,4 +12674,28 @@ objc_finish_foreach_loop (location_t location, tree object_expression, tree coll
   /* Done by c-parser.c  */
 }
 
+/* Return true if we have an NxString object pointer.  */
+
+bool
+objc_string_ref_type_p (tree strp)
+{
+  tree tmv;
+  if (!strp || TREE_CODE (strp) != POINTER_TYPE)
+    return false;
+
+  tmv = TYPE_MAIN_VARIANT (TREE_TYPE (strp));
+  tmv = OBJC_TYPE_NAME (tmv);
+  return (tmv
+         && TREE_CODE (tmv) == IDENTIFIER_NODE
+         && IDENTIFIER_POINTER (tmv)
+         && !strncmp (IDENTIFIER_POINTER (tmv), "NSString", 8));
+}
+
+/* At present the behavior of this is undefined and it does nothing.  */
+void
+objc_check_format_arg (tree ARG_UNUSED (format_arg), 
+                      tree ARG_UNUSED (args_list))
+{
+}
+
 #include "gt-objc-objc-act.h"
index 7947961bf9e0ac62064d7aff043a97a847890b34..7e014c7e625edd45d973cfd17e006a5db21db785 100644 (file)
@@ -2648,10 +2648,40 @@ DEFHOOK
  bool, (size_t code, const char *arg, int value),
  default_handle_c_option)
 
-DEFHOOK
-(objc_construct_string,
- "Construct a constant string representation for @var{string}",
+/* Targets may provide a string object type that can be used within
+   and between C, C++, and Objective-C dialects.  */
+
+DEFHOOK
+(objc_construct_string_object,
+ "Targets may provide a string object type that can be used within\
+ and between C, C++ and their respective Objective-C dialects.\
+ A string object might, for example, embed encoding and length information.\
+ These objects are considered opaque to the compiler and handled as references.\
+ An ideal implementation makes the composition of the string object\
+ match that of the Objective-C @code{NSString} (@code{NXString} for GNUStep),\
+ allowing efficient interworking between C-only and Objective-C code.\
+ If a target implements string objects then this hook should return a\
+ reference to such an object constructed from the normal `C' string\
+ representation provided in @var{string}.\
+ At present, the hook is used by Objective-C only, to obtain a\
+ common-format string object when the target provides one.",
  tree, (tree string),
  NULL)
+DEFHOOK
+(string_object_ref_type_p,
+ "If a target implements string objects then this hook should return\
+ @code{true} if @var{stringref} is a valid reference to such an object.",
+ bool, (const_tree stringref),
+ hook_bool_const_tree_false)
 
+DEFHOOK
+(check_string_object_format_arg,
+ "If a target implements string objects then this hook should should\
+  provide a facility to check the function arguments in @var{args_list}\
+  against the format specifiers in @var{format_arg} where the type of\
+  @var{format_arg} is one recognized as a valid string reference type.",
+ void, (tree format_arg, tree args_list),
+ NULL)
 HOOK_VECTOR_END (C90_EMPTY_HACK)
index dbde8313206cb0ebf6a8bf1d0b1bafebf10a3edc..4db13137877ba1086a89b7e7f29313d17755fe32 100644 (file)
@@ -1,3 +1,13 @@
+2010-11-06  Iain Sandoe  <iains@gcc.gnu.org>
+
+       PR target/44981
+       * gcc.dg/darwin-cfstring-format-1.c: New.
+       * gcc.dg/warn-nsstring.c: New.
+       * objc.dg/fsf-nsstring-format-1.m: New.
+       * obj-c++.dg/fsf-nsstring-format-1.mm: New.
+       * obj-c++.dg/torture/strings/const-cfstring-1.mm: Update for darwin10
+       linker warning.
+
 2010-11-05  Jason Merrill  <jason@redhat.com>
 
        PR c++/45473
diff --git a/gcc/testsuite/gcc.dg/darwin-cfstring-format-1.c b/gcc/testsuite/gcc.dg/darwin-cfstring-format-1.c
new file mode 100644 (file)
index 0000000..8771d52
--- /dev/null
@@ -0,0 +1,36 @@
+/* Check CFString format extensions.  */
+/* { dg-do compile { target *-*-darwin* } } */
+/* { dg-options "-Wall" } */
+
+extern int printf (const char *fmt, ...);
+
+typedef const struct __CFString * CFStringRef;
+
+#ifdef __CONSTANT_CFSTRINGS__
+#define CFSTR(cStr)  ((CFStringRef) __builtin___CFStringMakeConstantString ("" cStr ""))
+#else
+#error requires CFString
+#endif
+
+int s1 (CFStringRef fmt, ...) __attribute__((format(CFString, 1, 2))) ; /* OK */
+int s2 (int a, CFStringRef fmt, ... ) __attribute__((format(__CFString__, 2, 3))) ; /* OK */
+
+int s2a (int a, CFStringRef fmt, ... ) __attribute__((format(CFString, 2, 2))) ; /* { dg-error "format string argument follows the args to be formatted" } */
+
+int s3 (const char *fmt, ... ) __attribute__((format(__CFString__, 1, 2))) ; /* { dg-error "format argument should be a .CFString. reference but a string was found" } */
+int s4 (CFStringRef fmt, ... ) __attribute__((format(printf, 1, 2))) ; /* { dg-error "found a .CFStringRef. but the format argument should be a string" } */
+
+char *s5 (char dum, char *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
+CFStringRef s6 (CFStringRef dum, CFStringRef fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
+
+char *s7 (int dum, void *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error "format string argument is not a string type" } */
+int s8 (CFStringRef dum, CFStringRef fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error "function does not return string type" } */
+
+void foo (void)
+{
+  CFStringRef notchk = CFSTR ("here is an unchecked %d %s string");
+  s1 (notchk, 5, 6, 7);
+  printf("this one is checked %d %s", 3, 4, 5); /* { dg-warning "format .%s. expects type .char .., but argument 3 has type .int." } */
+                       /* { dg-warning "too many arguments for format" "" { target *-*-* } 33 } */
+  printf(s5 (1, "and so is this %d %d %s", 3, 4, "hey", 6), 5, 6, 12);/* { dg-warning "format .%s. expects type .char .., but argument 4 has type .int." } */
+}
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/warn-nsstring.c b/gcc/testsuite/gcc.dg/warn-nsstring.c
new file mode 100644 (file)
index 0000000..3795fb7
--- /dev/null
@@ -0,0 +1,7 @@
+/* Check that the NSString format extension is rejected in c.  */
+/* { dg-do compile } */
+
+extern void NSLog (void *fmt, ...) __attribute__((format(__NSString__, 1, 2))); /* { dg-warning "is only allowed in Objective-C dialects" } */
+extern void NSLog1 (void *fmt, ...) __attribute__((format(NSString, 1, 2))); /* { dg-warning "is only allowed in Objective-C dialects" } */
+
+
index 776456d60926b583e1e2e658af0eb1a21b72dd3c..324995be725e571378ca9b6c2c2674b1e479d216 100644 (file)
@@ -223,8 +223,14 @@ proc dg-additional-files-options { options source } {
        set additional_sources ""
     }
     if { $additional_files != "" } then { 
-       regsub -all " " $additional_files " [file dirname $source]/" additional_files
+       regsub -all "^| " $additional_files " [file dirname $source]/" additional_files
        set to_download [concat $to_download $additional_files]
+       send_log "add files: $to_download\n"
+       if ![is_remote host] {
+           foreach file $to_download {
+               remote_download host $file
+           }
+       }
        set additional_files ""
     }
     if [is_remote host] {
diff --git a/gcc/testsuite/obj-c++.dg/fsf-nsstring-format-1.mm b/gcc/testsuite/obj-c++.dg/fsf-nsstring-format-1.mm
new file mode 100644 (file)
index 0000000..6e58e65
--- /dev/null
@@ -0,0 +1,51 @@
+/* Check NSString format extensions.  */
+/* { dg-do compile { target *-*-darwin* } } */
+/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */
+/* { dg-options "-Wall" } */
+
+#ifndef __CONSTANT_CFSTRINGS__
+#error requires CFString
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int printf (const char *fmt, ...);
+typedef const struct __CFString * CFStringRef;
+
+#ifdef __cplusplus
+}
+#endif
+
+@class NSString;
+
+int s1 (NSString *fmt, ...) __attribute__((format(NSString, 1, 2))) ; /* OK */
+/* A CFString can represent an NSString.  */
+int s1a (CFStringRef fmt, ...) __attribute__((format(NSString, 1, 2))) ; /* OK */
+/* But... it is possible that a CFString format might imply functionality that
+   is not present in objective-c.  */
+int s1b (NSString *fmt, ...) __attribute__((format(CFString, 1, 2))) ; /* { dg-error "format argument should be a .CFString. reference" } */
+
+int s2 (int a, NSString *fmt, ... ) __attribute__((format(__NSString__, 2, 3))) ; /* OK */
+
+int s2a (int a, NSString *fmt, ... ) __attribute__((format(NSString, 2, 2))) ; /* { dg-error "format string argument follows the args to be formatted" } */
+
+int s3 (const char *fmt, ... ) __attribute__((format(__NSString__, 1, 2))) ; /* { dg-error "format argument should be a .NSString. reference but a string was found" } */
+int s4 (NSString *fmt, ... ) __attribute__((format(printf, 1, 2))) ; /* { dg-error "found a .NSString. reference but the format argument should be a string" } */
+
+char *s5 (char dum, char *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
+NSString *s6 (NSString *dum, NSString *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
+
+char *s7 (int dum, void *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error "format string argument is not a string type" } */
+int s8 (NSString *dum, NSString *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error "function does not return string type" } */
+
+char *s9 (int dum, char *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
+NSString *s10 (int dum, NSString *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
+
+void foo (void)
+{
+  s1 (@"this format not checked %d %s", 3, 4);
+  printf("this one is checked %d %s", 3, 4, 5); /* { dg-warning "format .%s. expects type .char.., but argument 3 has type 'int'" } */
+                       /* { dg-warning "too many arguments for format" "" { target *-*-* } 48 } */
+  printf(s9 (1, (char *)"and so is this %d %d %s" , 3, 4, "hm"), 5, 6, 12); /* { dg-warning "format .%s. expects type .char.., but argument 4 has type .int." } */
+}
index a11b5266f40e7eb8c9054f349aea03915f1edbcb..2983c43c445a0e43b4c70c5459e2f669f26ae2b4 100644 (file)
@@ -9,6 +9,9 @@
 /* { dg-skip-if "NeXT only" { *-*-* } { "-fgnu-runtime" } { "" } } */
 /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
 /* { dg-options "-mconstant-cfstrings -framework Cocoa" } */
+/* Darwin10's linker emits a warning that the constant strings are incompatible with writable ones.
+   well, we don't implement writable ones at this juncture.  */
+/* { dg-options "-mconstant-cfstrings -framework Cocoa -Wl,-w" { target *-*-darwin[123]* } } */
 
 #import <Foundation/NSString.h>
 #import <CoreFoundation/CFString.h>
diff --git a/gcc/testsuite/objc.dg/fsf-nsstring-format-1.m b/gcc/testsuite/objc.dg/fsf-nsstring-format-1.m
new file mode 100644 (file)
index 0000000..2550a55
--- /dev/null
@@ -0,0 +1,44 @@
+/* Check NSString format extensions.  */
+/* { dg-do compile { target *-*-darwin* } } */
+/* { dg-skip-if "" { *-*-* } { "-fgnu-runtime" } { "" } } */
+/* { dg-options "-Wall" } */
+
+extern int printf (const char *fmt, ...);
+
+#ifndef __CONSTANT_CFSTRINGS__
+#error requires CFString
+#endif
+
+typedef const struct __CFString * CFStringRef;
+@class NSString;
+
+int s1 (NSString *fmt, ...) __attribute__((format(NSString, 1, 2))) ; /* OK */
+/* A CFString can represent an NSString.  */
+int s1a (CFStringRef fmt, ...) __attribute__((format(NSString, 1, 2))) ; /* OK */
+/* But... it is possible that a CFString format might imply functionality that
+   is not present in objective-c.  */
+int s1b (NSString *fmt, ...) __attribute__((format(CFString, 1, 2))) ; /* { dg-error "format argument should be a .CFString. reference" } */
+
+int s2 (int a, NSString *fmt, ... ) __attribute__((format(__NSString__, 2, 3))) ; /* OK */
+
+int s2a (int a, NSString *fmt, ... ) __attribute__((format(NSString, 2, 2))) ; /* { dg-error "format string argument follows the args to be formatted" } */
+
+int s3 (const char *fmt, ... ) __attribute__((format(__NSString__, 1, 2))) ; /* { dg-error "format argument should be a .NSString. reference but a string was found" } */
+int s4 (NSString *fmt, ... ) __attribute__((format(printf, 1, 2))) ; /* { dg-error "found a .NSString. reference but the format argument should be a string" } */
+
+char *s5 (char dum, char *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
+NSString *s6 (NSString *dum, NSString *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
+
+char *s7 (int dum, void *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error "format string argument is not a string type" } */
+int s8 (NSString *dum, NSString *fmt1, ... ) __attribute__((format_arg(2))) ; /* { dg-error "function does not return string type" } */
+
+char *s9 (int dum, char *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
+NSString *s10 (int dum, NSString *fmt1, ... ) __attribute__((format_arg(2))) ; /* OK */
+
+void foo (void)
+{
+  s1 (@"format not checked %d %s", 3, 4);
+  printf("this one is checked %d %s", 3, 4, 5); /* { dg-warning "format .%s. expects type .char .., but argument 3 has type .int." } */
+                       /* { dg-warning "too many arguments for format" "" { target *-*-* } 41 } */
+  printf(s9 (1, "and so is this %d %d %s", 3, 4), 5, 6, 12); /* { dg-warning "format .%s. expects type .char .., but argument 4 has type .int." } */
+}