diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index fa0bbc83a1e..3156e35f39b 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,8 @@ +2019-10-01 Richard Sandiford + + * c-objc-common.c (useful_aka_type_p): New function. + (print_type): Use it to decide whether an aka type is worth printing. + 2019-09-27 Jakub Jelinek PR c++/88203 diff --git a/gcc/c/c-objc-common.c b/gcc/c/c-objc-common.c index 2b76737a74a..e1f3b2ee436 100644 --- a/gcc/c/c-objc-common.c +++ b/gcc/c/c-objc-common.c @@ -62,6 +62,73 @@ c_objc_common_init (void) return c_common_init (); } +/* Return true if it's worth saying that TYPE1 is also known as TYPE2. */ + +static bool +useful_aka_type_p (tree type1, tree type2) +{ + 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 (typedef_variant_p (type1)) + { + /* Saying that "foo" is also known as "struct foo" or + "struct " 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); + if ((code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE) + && (!id2 || TYPE_IDENTIFIER (type1) == id2)) + return false; + + return true; + } + else + { + switch (TREE_CODE (type1)) + { + case POINTER_TYPE: + case REFERENCE_TYPE: + return useful_aka_type_p (TREE_TYPE (type1), TREE_TYPE (type2)); + + case ARRAY_TYPE: + return (useful_aka_type_p (TYPE_DOMAIN (type1), TYPE_DOMAIN (type2)) + || useful_aka_type_p (TREE_TYPE (type1), TREE_TYPE (type2))); + + case FUNCTION_TYPE: + { + tree args1 = TYPE_ARG_TYPES (type1); + tree args2 = TYPE_ARG_TYPES (type2); + while (args1 != args2) + { + /* 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); + } + return useful_aka_type_p (TREE_TYPE (type1), TREE_TYPE (type2)); + } + + default: + return true; + } + } +} + /* Print T to CPP. */ static void @@ -83,7 +150,7 @@ 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) && t != TYPE_CANONICAL (t)) + if (TYPE_CANONICAL (t) && useful_aka_type_p (t, TYPE_CANONICAL (t))) { c_pretty_printer cpp2; /* Print the stripped version into a temporary printer. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index af7f6a25a02..891b2bf5e4b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-10-01 Richard Sandiford + + * gcc.dg/diag-aka-1.c (T): Turn into a pointer typedef. + (foo): Update accordingly. + * gcc.dg/diag-aka-4.c: New test. + 2019-10-01 Richard Sandiford * gcc.dg/diag-aka-3.c: New test. diff --git a/gcc/testsuite/gcc.dg/diag-aka-1.c b/gcc/testsuite/gcc.dg/diag-aka-1.c index fde4ca7c743..3383c1c263b 100644 --- a/gcc/testsuite/gcc.dg/diag-aka-1.c +++ b/gcc/testsuite/gcc.dg/diag-aka-1.c @@ -2,7 +2,7 @@ /* { dg-options "-Wc++-compat" } */ typedef struct A { int i; } B; -typedef struct T { int i; } T; +typedef struct T { int i; } *T; /* { dg-warning "using 'T' as both a typedef and a tag is invalid" } */ typedef const float TFA; typedef TFA TFB; typedef TFB TFC; @@ -24,6 +24,6 @@ bar (B *b, int *i) int foo (void *a) { - T *t = a; /* { dg-warning "request for implicit conversion from 'void \\*' to 'T \\*' {aka 'struct T \\*'} not" } */ + T t = a; /* { dg-warning "request for implicit conversion from 'void \\*' to 'T' {aka 'struct T \\*'} not" } */ return t->i; } diff --git a/gcc/testsuite/gcc.dg/diag-aka-4.c b/gcc/testsuite/gcc.dg/diag-aka-4.c new file mode 100644 index 00000000000..cf98dd96a53 --- /dev/null +++ b/gcc/testsuite/gcc.dg/diag-aka-4.c @@ -0,0 +1,72 @@ +typedef struct struct_wrapper { int i; } struct_wrapper; +typedef struct { int i; } anon_struct_wrapper; + +typedef union union_wrapper { int i; } union_wrapper; +typedef union { int i; } anon_union_wrapper; + +typedef enum enum_wrapper { A, B } enum_wrapper; +typedef enum { C, D } anon_enum_wrapper; + +void test_struct_wrapper (struct_wrapper y, int x) +{ + struct_wrapper *ptr = &x; /* { dg-error {initialization of 'struct_wrapper \*' from incompatible pointer type 'int \*'} } */ + const struct_wrapper *const_ptr = &x; /* { dg-error {initialization of 'const struct_wrapper \*' from incompatible pointer type 'int \*'} } */ + volatile struct_wrapper *volatile_ptr = &x; /* { dg-error {initialization of 'volatile struct_wrapper \*' from incompatible pointer type 'int \*'} } */ + struct_wrapper (*aptr)[10] = &x; /* { dg-error {initialization of 'struct_wrapper \(\*\)\[10\]' from incompatible pointer type 'int \*'} } */ + struct_wrapper (*f1)(int) = &x; /* { dg-error {initialization of 'struct_wrapper \(\*\)\(int\)' from incompatible pointer type 'int \*'} } */ + int (*f2)(struct_wrapper) = &x; /* { dg-error {initialization of 'int \(\*\)\(struct_wrapper\)' from incompatible pointer type 'int \*'} } */ + y = x; /* { dg-error {incompatible types when assigning to type 'struct_wrapper' from type 'int'} } */ +} + +void test_anon_struct_wrapper (anon_struct_wrapper y, int x) +{ + anon_struct_wrapper *ptr = &x; /* { dg-error {initialization of 'anon_struct_wrapper \*' from incompatible pointer type 'int \*'} } */ + const anon_struct_wrapper *const_ptr = &x; /* { dg-error {initialization of 'const anon_struct_wrapper \*' from incompatible pointer type 'int \*'} } */ + volatile anon_struct_wrapper *volatile_ptr = &x; /* { dg-error {initialization of 'volatile anon_struct_wrapper \*' from incompatible pointer type 'int \*'} } */ + anon_struct_wrapper (*aptr)[10] = &x; /* { dg-error {initialization of 'anon_struct_wrapper \(\*\)\[10\]' from incompatible pointer type 'int \*'} } */ + anon_struct_wrapper (*f1)(int) = &x; /* { dg-error {initialization of 'anon_struct_wrapper \(\*\)\(int\)' from incompatible pointer type 'int \*'} } */ + int (*f2)(anon_struct_wrapper) = &x; /* { dg-error {initialization of 'int \(\*\)\(anon_struct_wrapper\)' from incompatible pointer type 'int \*'} } */ + y = x; /* { dg-error {incompatible types when assigning to type 'anon_struct_wrapper' from type 'int'} } */ +} + +void test_union_wrapper (union_wrapper y, int x) +{ + union_wrapper *ptr = &x; /* { dg-error {initialization of 'union_wrapper \*' from incompatible pointer type 'int \*'} } */ + const union_wrapper *const_ptr = &x; /* { dg-error {initialization of 'const union_wrapper \*' from incompatible pointer type 'int \*'} } */ + volatile union_wrapper *volatile_ptr = &x; /* { dg-error {initialization of 'volatile union_wrapper \*' from incompatible pointer type 'int \*'} } */ + union_wrapper (*aptr)[10] = &x; /* { dg-error {initialization of 'union_wrapper \(\*\)\[10\]' from incompatible pointer type 'int \*'} } */ + union_wrapper (*f1)(int) = &x; /* { dg-error {initialization of 'union_wrapper \(\*\)\(int\)' from incompatible pointer type 'int \*'} } */ + int (*f2)(union_wrapper) = &x; /* { dg-error {initialization of 'int \(\*\)\(union_wrapper\)' from incompatible pointer type 'int \*'} } */ + y = x; /* { dg-error {incompatible types when assigning to type 'union_wrapper' from type 'int'} } */ +} + +void test_anon_union_wrapper (anon_union_wrapper y, int x) +{ + anon_union_wrapper *ptr = &x; /* { dg-error {initialization of 'anon_union_wrapper \*' from incompatible pointer type 'int \*'} } */ + const anon_union_wrapper *const_ptr = &x; /* { dg-error {initialization of 'const anon_union_wrapper \*' from incompatible pointer type 'int \*'} } */ + volatile anon_union_wrapper *volatile_ptr = &x; /* { dg-error {initialization of 'volatile anon_union_wrapper \*' from incompatible pointer type 'int \*'} } */ + anon_union_wrapper (*aptr)[10] = &x; /* { dg-error {initialization of 'anon_union_wrapper \(\*\)\[10\]' from incompatible pointer type 'int \*'} } */ + anon_union_wrapper (*f1)(int) = &x; /* { dg-error {initialization of 'anon_union_wrapper \(\*\)\(int\)' from incompatible pointer type 'int \*'} } */ + int (*f2)(anon_union_wrapper) = &x; /* { dg-error {initialization of 'int \(\*\)\(anon_union_wrapper\)' from incompatible pointer type 'int \*'} } */ + y = x; /* { dg-error {incompatible types when assigning to type 'anon_union_wrapper' from type 'int'} } */ +} + +void test_enum_wrapper (enum_wrapper y, int x) +{ + enum_wrapper *ptr = &x; /* { dg-error {initialization of 'enum_wrapper \*' from incompatible pointer type 'int \*'} } */ + const enum_wrapper *const_ptr = &x; /* { dg-error {initialization of 'const enum_wrapper \*' from incompatible pointer type 'int \*'} } */ + volatile enum_wrapper *volatile_ptr = &x; /* { dg-error {initialization of 'volatile enum_wrapper \*' from incompatible pointer type 'int \*'} } */ + enum_wrapper (*aptr)[10] = &x; /* { dg-error {initialization of 'enum_wrapper \(\*\)\[10\]' from incompatible pointer type 'int \*'} } */ + enum_wrapper (*f1)(int) = &x; /* { dg-error {initialization of 'enum_wrapper \(\*\)\(int\)' from incompatible pointer type 'int \*'} } */ + int (*f2)(enum_wrapper) = &x; /* { dg-error {initialization of 'int \(\*\)\(enum_wrapper\)' from incompatible pointer type 'int \*'} } */ +} + +void test_anon_enum_wrapper (anon_enum_wrapper y, int x) +{ + anon_enum_wrapper *ptr = &x; /* { dg-error {initialization of 'anon_enum_wrapper \*' from incompatible pointer type 'int \*'} } */ + const anon_enum_wrapper *const_ptr = &x; /* { dg-error {initialization of 'const anon_enum_wrapper \*' from incompatible pointer type 'int \*'} } */ + volatile anon_enum_wrapper *volatile_ptr = &x; /* { dg-error {initialization of 'volatile anon_enum_wrapper \*' from incompatible pointer type 'int \*'} } */ + anon_enum_wrapper (*aptr)[10] = &x; /* { dg-error {initialization of 'anon_enum_wrapper \(\*\)\[10\]' from incompatible pointer type 'int \*'} } */ + anon_enum_wrapper (*f1)(int) = &x; /* { dg-error {initialization of 'anon_enum_wrapper \(\*\)\(int\)' from incompatible pointer type 'int \*'} } */ + int (*f2)(anon_enum_wrapper) = &x; /* { dg-error {initialization of 'int \(\*\)\(anon_enum_wrapper\)' from incompatible pointer type 'int \*'} } */ +}