diff options
author | iains <iains@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-11-06 10:48:18 +0000 |
---|---|---|
committer | iains <iains@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-11-06 10:48:18 +0000 |
commit | 1f6616eece934619597d2f18a61518dcf46559e7 (patch) | |
tree | af63074e9f4040f49a64cedb2d17c074c3c9f236 /gcc/c-family | |
parent | aa1ff3cbb5bb2fa5eb13805cb5e519c65fe6d946 (diff) | |
download | gcc-1f6616eece934619597d2f18a61518dcf46559e7.tar.gz |
NS/CF String format syntax parsing.
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@166398 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/c-family')
-rw-r--r-- | gcc/c-family/ChangeLog | 21 | ||||
-rw-r--r-- | gcc/c-family/c-common.h | 2 | ||||
-rw-r--r-- | gcc/c-family/c-format.c | 192 | ||||
-rw-r--r-- | gcc/c-family/c-format.h | 7 | ||||
-rw-r--r-- | gcc/c-family/stub-objc.c | 14 |
5 files changed, 219 insertions, 17 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index c613ab36b8b..1164d919d0e 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -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. diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 13d9227ddca..58d3a321e0f 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -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++. */ diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c index e7fd2295d52..a64717a5510 100644 --- a/gcc/c-family/c-format.c +++ b/gcc/c-family/c-format.c @@ -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" /* 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) diff --git a/gcc/c-family/c-format.h b/gcc/c-family/c-format.h index 9d01f0af495..286219b16df 100644 --- a/gcc/c-family/c-format.h +++ b/gcc/c-family/c-format.h @@ -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 diff --git a/gcc/c-family/stub-objc.c b/gcc/c-family/stub-objc.c index 1f3b854f0c0..9dd6ef52f89 100644 --- a/gcc/c-family/stub-objc.c +++ b/gcc/c-family/stub-objc.c @@ -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)) +{ +} |