As David noted several weeks ago, we broke the sprintf warnings in the testsuite on AIX and more generally on targets with 2 byte wide characters.
This patch removes the hardcoded size of 4 bytes for a wchar. Instead it re-purposes an existing routine from the Fortran front-end which will return a standard C type for a given string. ie, if I pass the routine "short int", it returns short_integer_type_node. This allows us to solve the wchar problem because MODIFIED_WCHAR_TYPE uses types like "short int", "int", "unsigned int", etc to describe a wchar. So we just pass MODIFIED_WCHAR_TYPE to get_typenode_from_name and we get back a suitable type_node. We can then look at the size of the returned type node. Spot tested on aix 7. Bootstrapped and regression tested on x86-64. Installing on the trunk momentarily. Jeff
* gimple-ssa-sprintf.c (format_string): Do not hardcode size of target's wchar_t. * tree.c (get_typenode_from_name): Moved from fortran/trans-types.c. * tree.h (get_typenode_from_name): Prototype. * trans-types.c (get_typenode_from_name): Moved into gcc/tree.c. diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c index 46f6d8c03a6..1a813eaf4d4 100644 --- a/gcc/fortran/trans-types.c +++ b/gcc/fortran/trans-types.c @@ -218,43 +218,6 @@ get_int_kind_from_node (tree type) return -1; } -/* Return a typenode for the "standard" C type with a given name. */ -static tree -get_typenode_from_name (const char *name) -{ - if (name == NULL || *name == '\0') - return NULL_TREE; - - if (strcmp (name, "char") == 0) - return char_type_node; - if (strcmp (name, "unsigned char") == 0) - return unsigned_char_type_node; - if (strcmp (name, "signed char") == 0) - return signed_char_type_node; - - if (strcmp (name, "short int") == 0) - return short_integer_type_node; - if (strcmp (name, "short unsigned int") == 0) - return short_unsigned_type_node; - - if (strcmp (name, "int") == 0) - return integer_type_node; - if (strcmp (name, "unsigned int") == 0) - return unsigned_type_node; - - if (strcmp (name, "long int") == 0) - return long_integer_type_node; - if (strcmp (name, "long unsigned int") == 0) - return long_unsigned_type_node; - - if (strcmp (name, "long long int") == 0) - return long_long_integer_type_node; - if (strcmp (name, "long long unsigned int") == 0) - return long_long_unsigned_type_node; - - gcc_unreachable (); -} - static int get_int_kind_from_name (const char *name) { diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c index 88e952828e1..471bfc45eb8 100644 --- a/gcc/gimple-ssa-sprintf.c +++ b/gcc/gimple-ssa-sprintf.c @@ -2179,7 +2179,19 @@ format_string (const directive &dir, tree arg, vr_values *) fmtresult res; /* Compute the range the argument's length can be in. */ - int count_by = dir.specifier == 'S' || dir.modifier == FMT_LEN_l ? 4 : 1; + int count_by = 1; + if (dir.specifier == 'S' || dir.modifier == FMT_LEN_l) + { + /* Get a node for a C type that will be the same size + as a wchar_t on the target. */ + tree node = get_typenode_from_name (MODIFIED_WCHAR_TYPE); + + /* Now that we have a suitable node, get the number of + bytes it occupies. */ + count_by = int_size_in_bytes (node); + gcc_checking_assert (count_by == 2 || count_by == 4); + } + fmtresult slen = get_string_length (arg, count_by); if (slen.range.min == slen.range.max && slen.range.min < HOST_WIDE_INT_MAX) diff --git a/gcc/tree.c b/gcc/tree.c index 748ece690ea..d7dca77d2b2 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -14408,6 +14408,43 @@ expr_type_first_operand_type_p (tree_code code) } } +/* Return a typenode for the "standard" C type with a given name. */ +tree +get_typenode_from_name (const char *name) +{ + if (name == NULL || *name == '\0') + return NULL_TREE; + + if (strcmp (name, "char") == 0) + return char_type_node; + if (strcmp (name, "unsigned char") == 0) + return unsigned_char_type_node; + if (strcmp (name, "signed char") == 0) + return signed_char_type_node; + + if (strcmp (name, "short int") == 0) + return short_integer_type_node; + if (strcmp (name, "short unsigned int") == 0) + return short_unsigned_type_node; + + if (strcmp (name, "int") == 0) + return integer_type_node; + if (strcmp (name, "unsigned int") == 0) + return unsigned_type_node; + + if (strcmp (name, "long int") == 0) + return long_integer_type_node; + if (strcmp (name, "long unsigned int") == 0) + return long_unsigned_type_node; + + if (strcmp (name, "long long int") == 0) + return long_long_integer_type_node; + if (strcmp (name, "long long unsigned int") == 0) + return long_long_unsigned_type_node; + + gcc_unreachable (); +} + /* List of pointer types used to declare builtins before we have seen their real declaration. diff --git a/gcc/tree.h b/gcc/tree.h index a0f24b61ef1..1e59dd59cf3 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -4987,6 +4987,9 @@ extern tree get_base_address (tree t); of EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */ extern tree array_ref_element_size (tree); +/* Return a typenode for the "standard" C type with a given name. */ +extern tree get_typenode_from_name (const char *); + /* Return a tree representing the upper bound of the array mentioned in EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */ extern tree array_ref_up_bound (tree);