diff options
author | Richard Sandiford <richard.sandiford@arm.com> | 2019-10-14 08:05:52 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2019-10-14 08:05:52 +0000 |
commit | 56898e437a538c7edc0724a3650f5cb81c9d5721 (patch) | |
tree | 94c4cbef454873ea3d58380d67930ee520289c86 /gcc/c/c-objc-common.c | |
parent | b9424661f58de6c0aa9dc4c855c1fd913cc06282 (diff) | |
download | gcc-56898e437a538c7edc0724a3650f5cb81c9d5721.zip gcc-56898e437a538c7edc0724a3650f5cb81c9d5721.tar.gz gcc-56898e437a538c7edc0724a3650f5cb81c9d5721.tar.bz2 |
[C] Avoid exposing internal details in aka types
The current aka diagnostics can sometimes leak internal details that
seem more likely to be distracting than useful. E.g. on aarch64:
void f (va_list *va) { *va = 1; }
gives:
incompatible types when assigning to type ‘va_list’ {aka ‘__va_list’} from type ‘int’
where __va_list isn't something the user is expected to know about.
A similar thing happens for C++ on the arm_neon.h-based:
float x;
int8x8_t y = x;
which gives:
cannot convert ‘float’ to ‘int8x8_t’ {aka ‘__Int8x8_t’} in initialization
This is accurate -- and __Int8x8_t is defined by the AArch64 PCS --
but it's not going to be meaningful to most users.
This patch stops the aka code looking through typedefs if all of
the following are true:
(1) the typedef is built into the compiler or comes from a system header
(2) the target of the typedef is anonymous or has a name in the
implementation namespace
(3) the target type is a tag type or vector type, which have in common that:
(a) we print their type names if they have one
(b) what we print for anonymous types isn't all that useful
("struct <anonymous>" etc. for tag types, pseudo-C "__vector(N) T"
for vector types)
The patch does this by recursively looking for the aka type, like the
C++ frontend already does. This in turn makes "aka" work for distinct type
copies like __Int8x8_t on aarch64, fixing the ??? in aarch64/diag_aka_1.c.
2019-10-14 Richard Sandiford <richard.sandiford@arm.com>
gcc/c-family/
* c-common.h (user_facing_original_type_p): Declare.
* c-common.c: Include c-spellcheck.h.
(user_facing_original_type_p): New function.
gcc/c/
* c-objc-common.c (useful_aka_type_p): Replace with...
(get_aka_type): ...this new function. Given the original type,
decide which aka type to print (if any). Only look through typedefs
if user_facing_original_type_p.
(print_type): Update accordingly.
gcc/testsuite/
* gcc.dg/diag-aka-5.h: New test.
* gcc.dg/diag-aka-5a.c: Likewise.
* gcc.dg/diag-aka-5b.c: Likewise.
* gcc.target/aarch64/diag_aka_1.c (f): Expect an aka to be printed
for myvec.
From-SVN: r276951
Diffstat (limited to 'gcc/c/c-objc-common.c')
-rw-r--r-- | gcc/c/c-objc-common.c | 130 |
1 files changed, 91 insertions, 39 deletions
diff --git a/gcc/c/c-objc-common.c b/gcc/c/c-objc-common.c index e1f3b2e..10d72c5 100644 --- a/gcc/c/c-objc-common.c +++ b/gcc/c/c-objc-common.c @@ -28,6 +28,8 @@ along with GCC; see the file COPYING3. If not see #include "langhooks.h" #include "c-objc-common.h" #include "gcc-rich-location.h" +#include "stringpool.h" +#include "attribs.h" static bool c_tree_printer (pretty_printer *, text_info *, const char *, int, bool, bool, bool, bool *, const char **); @@ -62,71 +64,120 @@ c_objc_common_init (void) return c_common_init (); } -/* Return true if it's worth saying that TYPE1 is also known as TYPE2. */ +/* Decide whether it's worth saying that TYPE is also known as some other + type. Return the other type if so, otherwise return TYPE. */ -static bool -useful_aka_type_p (tree type1, tree type2) +static tree +get_aka_type (tree type) { - if (type1 == type2) - return false; - - if (type1 == error_mark_node || type2 == error_mark_node) - return false; - - if (TREE_CODE (type1) != TREE_CODE (type2)) - return true; + if (type == error_mark_node) + return type; - if (typedef_variant_p (type1)) + tree result; + if (typedef_variant_p (type)) { /* Saying that "foo" is also known as "struct foo" or "struct <anonymous>" is unlikely to be useful, since users of structure-like types would already know that they're structures. The same applies to unions and enums; in general, printing the tag is only useful if it has a different name. */ - tree_code code = TREE_CODE (type2); - tree id2 = TYPE_IDENTIFIER (type2); + tree orig_type = DECL_ORIGINAL_TYPE (TYPE_NAME (type)); + tree_code code = TREE_CODE (orig_type); + tree orig_id = TYPE_IDENTIFIER (orig_type); if ((code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE) - && (!id2 || TYPE_IDENTIFIER (type1) == id2)) - return false; + && (!orig_id || TYPE_IDENTIFIER (type) == orig_id)) + return type; - return true; + if (!user_facing_original_type_p (type)) + return type; + + result = get_aka_type (orig_type); } else { - switch (TREE_CODE (type1)) + tree canonical = TYPE_CANONICAL (type); + if (canonical && TREE_CODE (type) != TREE_CODE (canonical)) + return canonical; + + /* Recursive calls might choose a middle ground between TYPE + (which has no typedefs stripped) and CANONICAL (which has + all typedefs stripped). So try to reuse TYPE or CANONICAL if + convenient, but be prepared to create a new type if necessary. */ + switch (TREE_CODE (type)) { case POINTER_TYPE: case REFERENCE_TYPE: - return useful_aka_type_p (TREE_TYPE (type1), TREE_TYPE (type2)); + { + tree target_type = get_aka_type (TREE_TYPE (type)); + + if (target_type == TREE_TYPE (type)) + return type; + + if (canonical && target_type == TREE_TYPE (canonical)) + return canonical; + + result = (TREE_CODE (type) == POINTER_TYPE + ? build_pointer_type (target_type) + : build_reference_type (target_type)); + break; + } case ARRAY_TYPE: - return (useful_aka_type_p (TYPE_DOMAIN (type1), TYPE_DOMAIN (type2)) - || useful_aka_type_p (TREE_TYPE (type1), TREE_TYPE (type2))); + { + tree element_type = get_aka_type (TREE_TYPE (type)); + tree index_type = (TYPE_DOMAIN (type) + ? get_aka_type (TYPE_DOMAIN (type)) + : NULL_TREE); + + if (element_type == TREE_TYPE (type) + && index_type == TYPE_DOMAIN (type)) + return type; + + if (canonical + && element_type == TREE_TYPE (canonical) + && index_type == TYPE_DOMAIN (canonical)) + return canonical; + + result = build_array_type (element_type, index_type, + TYPE_TYPELESS_STORAGE (type)); + break; + } case FUNCTION_TYPE: { - tree args1 = TYPE_ARG_TYPES (type1); - tree args2 = TYPE_ARG_TYPES (type2); - while (args1 != args2) + tree return_type = get_aka_type (TREE_TYPE (type)); + + tree args = TYPE_ARG_TYPES (type); + if (args == error_mark_node) + return type; + + auto_vec<tree, 32> arg_types; + bool type_ok_p = true; + while (args && args != void_list_node) { - /* Although this shouldn't happen, it seems to wrong to assert - for it in a diagnostic routine. */ - if (!args1 || args1 == void_type_node) - return true; - if (!args2 || args2 == void_type_node) - return true; - if (useful_aka_type_p (TREE_VALUE (args1), TREE_VALUE (args2))) - return true; - args1 = TREE_CHAIN (args1); - args2 = TREE_CHAIN (args2); + tree arg_type = get_aka_type (TREE_VALUE (args)); + arg_types.safe_push (arg_type); + type_ok_p &= (arg_type == TREE_VALUE (args)); + args = TREE_CHAIN (args); } - return useful_aka_type_p (TREE_TYPE (type1), TREE_TYPE (type2)); + + if (type_ok_p && return_type == TREE_TYPE (type)) + return type; + + unsigned int i; + tree arg_type; + FOR_EACH_VEC_ELT_REVERSE (arg_types, i, arg_type) + args = tree_cons (NULL_TREE, arg_type, args); + result = build_function_type (return_type, args); + break; } default: - return true; + return canonical ? canonical : type; } } + return build_type_attribute_qual_variant (result, TYPE_ATTRIBUTES (type), + TYPE_QUALS (type)); } /* Print T to CPP. */ @@ -150,11 +201,12 @@ print_type (c_pretty_printer *cpp, tree t, bool *quoted) stripped version. But sometimes the stripped version looks exactly the same, so we don't want it after all. To avoid printing it in that case, we play ugly obstack games. */ - if (TYPE_CANONICAL (t) && useful_aka_type_p (t, TYPE_CANONICAL (t))) + tree aka_type = get_aka_type (t); + if (aka_type != t) { c_pretty_printer cpp2; /* Print the stripped version into a temporary printer. */ - cpp2.type_id (TYPE_CANONICAL (t)); + cpp2.type_id (aka_type); struct obstack *ob2 = cpp2.buffer->obstack; /* Get the stripped version from the temporary printer. */ const char *aka = (char *) obstack_base (ob2); @@ -174,7 +226,7 @@ print_type (c_pretty_printer *cpp, tree t, bool *quoted) pp_c_whitespace (cpp); if (*quoted) pp_begin_quote (cpp, pp_show_color (cpp)); - cpp->type_id (TYPE_CANONICAL (t)); + cpp->type_id (aka_type); if (*quoted) pp_end_quote (cpp, pp_show_color (cpp)); pp_right_brace (cpp); |