aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2019-10-14 08:05:52 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2019-10-14 08:05:52 +0000
commit56898e437a538c7edc0724a3650f5cb81c9d5721 (patch)
tree94c4cbef454873ea3d58380d67930ee520289c86
parentb9424661f58de6c0aa9dc4c855c1fd913cc06282 (diff)
downloadgcc-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
-rw-r--r--gcc/c-family/ChangeLog6
-rw-r--r--gcc/c-family/c-common.c47
-rw-r--r--gcc/c-family/c-common.h1
-rw-r--r--gcc/c/ChangeLog8
-rw-r--r--gcc/c/c-objc-common.c130
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/gcc.dg/diag-aka-5.h22
-rw-r--r--gcc/testsuite/gcc.dg/diag-aka-5a.c135
-rw-r--r--gcc/testsuite/gcc.dg/diag-aka-5b.c134
-rw-r--r--gcc/testsuite/gcc.target/aarch64/diag_aka_1.c5
10 files changed, 454 insertions, 42 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 2b63689..cb3b9cf 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,9 @@
+2019-10-14 Richard Sandiford <richard.sandiford@arm.com>
+
+ * c-common.h (user_facing_original_type_p): Declare.
+ * c-common.c: Include c-spellcheck.h.
+ (user_facing_original_type_p): New function.
+
2019-10-12 Jakub Jelinek <jakub@redhat.com>
* c-common.h (c_omp_mark_declare_variant,
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 909f52a..483d874 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimplify.h"
#include "substring-locations.h"
#include "spellcheck.h"
+#include "c-spellcheck.h"
#include "selftest.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
@@ -7713,6 +7714,52 @@ set_underlying_type (tree x)
}
}
+/* Return true if it is worth exposing the DECL_ORIGINAL_TYPE of TYPE to
+ the user in diagnostics, false if it would be better to use TYPE itself.
+ TYPE is known to satisfy typedef_variant_p. */
+
+bool
+user_facing_original_type_p (const_tree type)
+{
+ gcc_assert (typedef_variant_p (type));
+ tree decl = TYPE_NAME (type);
+
+ /* Look through any typedef in "user" code. */
+ if (!DECL_IN_SYSTEM_HEADER (decl) && !DECL_IS_BUILTIN (decl))
+ return true;
+
+ /* If the original type is also named and is in the user namespace,
+ assume it too is a user-facing type. */
+ tree orig_type = DECL_ORIGINAL_TYPE (decl);
+ if (tree orig_id = TYPE_IDENTIFIER (orig_type))
+ if (!name_reserved_for_implementation_p (IDENTIFIER_POINTER (orig_id)))
+ return true;
+
+ switch (TREE_CODE (orig_type))
+ {
+ /* Don't look through to an anonymous vector type, since the syntax
+ we use for them in diagnostics isn't real C or C++ syntax.
+ And if ORIG_TYPE is named but in the implementation namespace,
+ TYPE is likely to be more meaningful to the user. */
+ case VECTOR_TYPE:
+ return false;
+
+ /* Don't expose anonymous tag types that are presumably meant to be
+ known by their typedef name. Also don't expose tags that are in
+ the implementation namespace, such as:
+
+ typedef struct __foo foo; */
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case ENUMERAL_TYPE:
+ return false;
+
+ /* Look through to anything else. */
+ default:
+ return true;
+ }
+}
+
/* Record the types used by the current global variable declaration
being parsed, so that we can decide later to emit their debug info.
Those types are in types_used_by_cur_var_decl, and we are going to
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index db7f26e..3bc021b 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1063,6 +1063,7 @@ extern tree builtin_type_for_size (int, bool);
extern void c_common_mark_addressable_vec (tree);
extern void set_underlying_type (tree);
+extern bool user_facing_original_type_p (const_tree);
extern void record_types_used_by_current_var_decl (tree);
extern vec<tree, va_gc> *make_tree_vector (void);
extern void release_tree_vector (vec<tree, va_gc> *);
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index c76baf0..23310ce 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,11 @@
+2019-10-14 Richard Sandiford <richard.sandiford@arm.com>
+
+ * 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.
+
2019-10-14 Jakub Jelinek <jakub@redhat.com>
* c-parser.c (c_parser_omp_all_clauses): Change bool NESTED_P argument
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);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 5db77a7..7385c33 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2019-10-14 Richard Sandiford <richard.sandiford@arm.com>
+
+ * 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.
+
2019-10-14 Jakub Jelinek <jakub@redhat.com>
* c-c++-common/gomp/declare-variant-7.c: Add tests for clauses not
diff --git a/gcc/testsuite/gcc.dg/diag-aka-5.h b/gcc/testsuite/gcc.dg/diag-aka-5.h
new file mode 100644
index 0000000..0c7404d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/diag-aka-5.h
@@ -0,0 +1,22 @@
+#ifdef IS_SYSTEM_HEADER
+#pragma GCC system_header
+#endif
+
+typedef enum __internal_enum { A, B } user_enum;
+typedef user_enum *user_enum_ptr;
+
+typedef struct __internal_struct { int i; } user_struct;
+typedef user_struct user_struct_copy;
+typedef user_struct *user_struct_ptr;
+
+typedef union __internal_union { int i; } user_union;
+typedef user_union user_union_copy;
+typedef user_union *user_union_ptr;
+
+typedef unsigned int user_vector __attribute__((__vector_size__(16)));
+typedef user_vector user_vector_copy;
+typedef user_vector *user_vector_ptr;
+
+typedef int user_int;
+typedef user_int user_int_copy;
+typedef user_int *user_int_ptr;
diff --git a/gcc/testsuite/gcc.dg/diag-aka-5a.c b/gcc/testsuite/gcc.dg/diag-aka-5a.c
new file mode 100644
index 0000000..8768a79
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/diag-aka-5a.c
@@ -0,0 +1,135 @@
+#define IS_SYSTEM_HEADER
+#include "diag-aka-5.h"
+
+typedef user_enum user_enum_copy;
+
+struct s { int i; };
+
+user_enum ue1;
+user_enum_copy ue2;
+user_enum_ptr ue_ptr1;
+user_enum *ue_ptr2;
+const user_enum *const_ue_ptr1;
+const user_enum_copy *const_ue_ptr2;
+volatile user_enum *volatile_ue_ptr1;
+volatile user_enum_copy *volatile_ue_ptr2;
+__extension__ _Atomic user_enum *atomic_ue_ptr1;
+__extension__ _Atomic user_enum_copy *atomic_ue_ptr2;
+user_enum (*ue_array_ptr1)[10];
+user_enum_copy (*ue_array_ptr2)[10];
+user_enum (*ue_fn_ptr1) (void);
+void (*ue_fn_ptr2) (user_enum);
+void (*ue_fn_ptr3) (user_enum, ...);
+user_enum_copy (*ue_fn_ptr4) (void);
+void (*ue_fn_ptr5) (user_enum_copy);
+void (*ue_fn_ptr6) (user_enum_copy, ...);
+user_enum (*__attribute__((__transaction_unsafe__)) unsafe_ue_fn_ptr1) (void);
+user_enum_copy (*__attribute__((__transaction_unsafe__)) unsafe_ue_fn_ptr2) (void);
+
+user_struct us1;
+user_struct_copy us2;
+user_struct_ptr us_ptr1;
+user_struct *us_ptr2;
+const user_struct *const_us_ptr1;
+const user_struct_copy *const_us_ptr2;
+
+user_union uu1;
+user_union_copy uu2;
+user_union_ptr uu_ptr1;
+user_union *uu_ptr2;
+const user_union *const_uu_ptr1;
+const user_union_copy *const_uu_ptr2;
+
+user_vector uv1;
+user_vector_copy uv2;
+user_vector_ptr uv_ptr1;
+user_vector *uv_ptr2;
+const user_vector *const_uv_ptr1;
+const user_vector_copy *const_uv_ptr2;
+
+user_int ui1;
+user_int_copy ui2;
+user_int_ptr ui_ptr1;
+user_int *ui_ptr2;
+const user_int *const_ui_ptr1;
+const user_int_copy *const_ui_ptr2;
+volatile user_int *volatile_ui_ptr1;
+volatile user_int_copy *volatile_ui_ptr2;
+__extension__ _Atomic user_int *atomic_ui_ptr1;
+__extension__ _Atomic user_int_copy *atomic_ui_ptr2;
+user_int (*ui_array_ptr1)[10];
+user_int_copy (*ui_array_ptr2)[10];
+user_int (*ui_fn_ptr1) (void);
+void (*ui_fn_ptr2) (user_int);
+void (*ui_fn_ptr3) (user_int, ...);
+user_int_copy (*ui_fn_ptr4) (void);
+void (*ui_fn_ptr5) (user_int_copy);
+void (*ui_fn_ptr6) (user_int_copy, ...);
+user_int (*__attribute__((__transaction_unsafe__)) unsafe_ui_fn_ptr1) (void);
+user_int_copy (*__attribute__((__transaction_unsafe__)) unsafe_ui_fn_ptr2) (void);
+
+void f (struct s s)
+{
+ ue1 = s; /* { dg-error {assigning to type 'user_enum' from type 'struct s'} } */
+ ue2 = s; /* { dg-error {assigning to type 'user_enum_copy' {aka 'user_enum'} from type 'struct s'} } */
+ ue_ptr1 = &s; /* { dg-error {assignment to 'user_enum_ptr' {aka 'user_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ ue_ptr2 = &s; /* { dg-error {assignment to 'user_enum \*' from incompatible pointer type 'struct s \*'} } */
+ const_ue_ptr1 = &s; /* { dg-error {assignment to 'const user_enum \*' from incompatible pointer type 'struct s \*'} } */
+ const_ue_ptr2 = &s; /* { dg-error {assignment to 'const user_enum_copy \*' {aka 'const user_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ volatile_ue_ptr1 = &s; /* { dg-error {assignment to 'volatile user_enum \*' from incompatible pointer type 'struct s \*'} } */
+ volatile_ue_ptr2 = &s; /* { dg-error {assignment to 'volatile user_enum_copy \*' {aka 'volatile user_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ atomic_ue_ptr1 = &s; /* { dg-error {assignment to '_Atomic user_enum \*' from incompatible pointer type 'struct s \*'} } */
+ atomic_ue_ptr2 = &s; /* { dg-error {assignment to '_Atomic user_enum_copy \*' {aka '_Atomic user_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ ue_array_ptr1 = &s; /* { dg-error {assignment to 'user_enum \(\*\)\[10\]' from incompatible pointer type 'struct s \*'} } */
+ ue_array_ptr2 = &s; /* { dg-error {assignment to 'user_enum_copy \(\*\)\[10\]' {aka 'user_enum \(\*\)\[10\]'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr1 = &s; /* { dg-error {assignment to 'user_enum \(\*\)\(void\)' from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr2 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum\)' from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr3 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum, \.\.\.\)' from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr4 = &s; /* { dg-error {assignment to 'user_enum_copy \(\*\)\(void\)' {aka 'user_enum \(\*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr5 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum_copy\)' {aka 'void \(\*\)\(user_enum\)'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr6 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum_copy, \.\.\.\)' {aka 'void \(\*\)\(user_enum, \.\.\.\)'} from incompatible pointer type 'struct s \*'} } */
+ unsafe_ue_fn_ptr1 = &s; /* { dg-error {assignment to 'user_enum \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' from incompatible pointer type 'struct s \*'} } */
+ unsafe_ue_fn_ptr2 = &s; /* { dg-error {assignment to 'user_enum_copy \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' {aka 'user_enum \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+
+ us1 = s; /* { dg-error {assigning to type 'user_struct' from type 'struct s'} } */
+ us2 = s; /* { dg-error {assigning to type 'user_struct_copy' {aka 'user_struct'} from type 'struct s'} } */
+ us_ptr1 = &s; /* { dg-error {assignment to 'user_struct_ptr' {aka 'user_struct \*'} from incompatible pointer type 'struct s \*'} } */
+ us_ptr2 = &s; /* { dg-error {assignment to 'user_struct \*' from incompatible pointer type 'struct s \*'} } */
+ const_us_ptr1 = &s; /* { dg-error {assignment to 'const user_struct \*' from incompatible pointer type 'struct s \*'} } */
+ const_us_ptr2 = &s; /* { dg-error {assignment to 'const user_struct_copy \*' {aka 'const user_struct \*'} from incompatible pointer type 'struct s \*'} } */
+
+ uu1 = s; /* { dg-error {assigning to type 'user_union' from type 'struct s'} } */
+ uu2 = s; /* { dg-error {assigning to type 'user_union_copy' {aka 'user_union'} from type 'struct s'} } */
+ uu_ptr1 = &s; /* { dg-error {assignment to 'user_union_ptr' {aka 'user_union \*'} from incompatible pointer type 'struct s \*'} } */
+ uu_ptr2 = &s; /* { dg-error {assignment to 'user_union \*' from incompatible pointer type 'struct s \*'} } */
+ const_uu_ptr1 = &s; /* { dg-error {assignment to 'const user_union \*' from incompatible pointer type 'struct s \*'} } */
+ const_uu_ptr2 = &s; /* { dg-error {assignment to 'const user_union_copy \*' {aka 'const user_union \*'} from incompatible pointer type 'struct s \*'} } */
+
+ uv1 = s; /* { dg-error {assigning to type 'user_vector' from type 'struct s'} } */
+ uv2 = s; /* { dg-error {assigning to type 'user_vector_copy' {aka 'user_vector'} from type 'struct s'} } */
+ uv_ptr1 = &s; /* { dg-error {assignment to 'user_vector_ptr' {aka 'user_vector \*'} from incompatible pointer type 'struct s \*'} } */
+ uv_ptr2 = &s; /* { dg-error {assignment to 'user_vector \*' from incompatible pointer type 'struct s \*'} } */
+ const_uv_ptr1 = &s; /* { dg-error {assignment to 'const user_vector \*' from incompatible pointer type 'struct s \*'} } */
+ const_uv_ptr2 = &s; /* { dg-error {assignment to 'const user_vector_copy \*' {aka 'const user_vector \*'} from incompatible pointer type 'struct s \*'} } */
+
+ ui1 = s; /* { dg-error {assigning to type 'user_int' {aka 'int'} from type 'struct s'} } */
+ ui2 = s; /* { dg-error {assigning to type 'user_int_copy' {aka 'int'} from type 'struct s'} } */
+ ui_ptr1 = &s; /* { dg-error {assignment to 'user_int_ptr' {aka 'int \*'} from incompatible pointer type 'struct s \*'} } */
+ ui_ptr2 = &s; /* { dg-error {assignment to 'user_int \*' {aka 'int \*'} from incompatible pointer type 'struct s \*'} } */
+ const_ui_ptr1 = &s; /* { dg-error {assignment to 'const user_int \*' {aka 'const int \*'} from incompatible pointer type 'struct s \*'} } */
+ const_ui_ptr2 = &s; /* { dg-error {assignment to 'const user_int_copy \*' {aka 'const int \*'} from incompatible pointer type 'struct s \*'} } */
+ volatile_ui_ptr1 = &s; /* { dg-error {assignment to 'volatile user_int \*' {aka 'volatile int \*'} from incompatible pointer type 'struct s \*'} } */
+ volatile_ui_ptr2 = &s; /* { dg-error {assignment to 'volatile user_int_copy \*' {aka 'volatile int \*'} from incompatible pointer type 'struct s \*'} } */
+ atomic_ui_ptr1 = &s; /* { dg-error {assignment to '_Atomic user_int \*' {aka '_Atomic int \*'} from incompatible pointer type 'struct s \*'} } */
+ atomic_ui_ptr2 = &s; /* { dg-error {assignment to '_Atomic user_int_copy \*' {aka '_Atomic int \*'} from incompatible pointer type 'struct s \*'} } */
+ ui_array_ptr1 = &s; /* { dg-error {assignment to 'user_int \(\*\)\[10\]' {aka 'int \(\*\)\[10\]'} from incompatible pointer type 'struct s \*'} } */
+ ui_array_ptr2 = &s; /* { dg-error {assignment to 'user_int_copy \(\*\)\[10\]' {aka 'int \(\*\)\[10\]'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr1 = &s; /* { dg-error {assignment to 'user_int \(\*\)\(void\)' {aka 'int \(\*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr2 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int\)' {aka 'void \(\*\)\(int\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr3 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int, \.\.\.\)' {aka 'void \(\*\)\(int, \.\.\.\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr4 = &s; /* { dg-error {assignment to 'user_int_copy \(\*\)\(void\)' {aka 'int \(\*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr5 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int_copy\)' {aka 'void \(\*\)\(int\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr6 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int_copy, \.\.\.\)' {aka 'void \(\*\)\(int, \.\.\.\)'} from incompatible pointer type 'struct s \*'} } */
+ unsafe_ui_fn_ptr1 = &s; /* { dg-error {assignment to 'user_int \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' {aka 'int \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ unsafe_ui_fn_ptr2 = &s; /* { dg-error {assignment to 'user_int_copy \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' {aka 'int \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+}
diff --git a/gcc/testsuite/gcc.dg/diag-aka-5b.c b/gcc/testsuite/gcc.dg/diag-aka-5b.c
new file mode 100644
index 0000000..e0ec7c8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/diag-aka-5b.c
@@ -0,0 +1,134 @@
+#include "diag-aka-5.h"
+
+typedef user_enum user_enum_copy;
+
+struct s { int i; };
+
+user_enum ue1;
+user_enum_copy ue2;
+user_enum_ptr ue_ptr1;
+user_enum *ue_ptr2;
+const user_enum *const_ue_ptr1;
+const user_enum_copy *const_ue_ptr2;
+volatile user_enum *volatile_ue_ptr1;
+volatile user_enum_copy *volatile_ue_ptr2;
+__extension__ _Atomic user_enum *atomic_ue_ptr1;
+__extension__ _Atomic user_enum_copy *atomic_ue_ptr2;
+user_enum (*ue_array_ptr1)[10];
+user_enum_copy (*ue_array_ptr2)[10];
+user_enum (*ue_fn_ptr1) (void);
+void (*ue_fn_ptr2) (user_enum);
+void (*ue_fn_ptr3) (user_enum, ...);
+user_enum_copy (*ue_fn_ptr4) (void);
+void (*ue_fn_ptr5) (user_enum_copy);
+void (*ue_fn_ptr6) (user_enum_copy, ...);
+user_enum (*__attribute__((__transaction_unsafe__)) unsafe_ue_fn_ptr1) (void);
+user_enum_copy (*__attribute__((__transaction_unsafe__)) unsafe_ue_fn_ptr2) (void);
+
+user_struct us1;
+user_struct_copy us2;
+user_struct_ptr us_ptr1;
+user_struct *us_ptr2;
+const user_struct *const_us_ptr1;
+const user_struct_copy *const_us_ptr2;
+
+user_union uu1;
+user_union_copy uu2;
+user_union_ptr uu_ptr1;
+user_union *uu_ptr2;
+const user_union *const_uu_ptr1;
+const user_union_copy *const_uu_ptr2;
+
+user_vector uv1;
+user_vector_copy uv2;
+user_vector_ptr uv_ptr1;
+user_vector *uv_ptr2;
+const user_vector *const_uv_ptr1;
+const user_vector_copy *const_uv_ptr2;
+
+user_int ui1;
+user_int_copy ui2;
+user_int_ptr ui_ptr1;
+user_int *ui_ptr2;
+const user_int *const_ui_ptr1;
+const user_int_copy *const_ui_ptr2;
+volatile user_int *volatile_ui_ptr1;
+volatile user_int_copy *volatile_ui_ptr2;
+__extension__ _Atomic user_int *atomic_ui_ptr1;
+__extension__ _Atomic user_int_copy *atomic_ui_ptr2;
+user_int (*ui_array_ptr1)[10];
+user_int_copy (*ui_array_ptr2)[10];
+user_int (*ui_fn_ptr1) (void);
+void (*ui_fn_ptr2) (user_int);
+void (*ui_fn_ptr3) (user_int, ...);
+user_int_copy (*ui_fn_ptr4) (void);
+void (*ui_fn_ptr5) (user_int_copy);
+void (*ui_fn_ptr6) (user_int_copy, ...);
+user_int (*__attribute__((__transaction_unsafe__)) unsafe_ui_fn_ptr1) (void);
+user_int_copy (*__attribute__((__transaction_unsafe__)) unsafe_ui_fn_ptr2) (void);
+
+void f (struct s s)
+{
+ ue1 = s; /* { dg-error {assigning to type 'user_enum' {aka 'enum __internal_enum'} from type 'struct s'} } */
+ ue2 = s; /* { dg-error {assigning to type 'user_enum_copy' {aka 'enum __internal_enum'} from type 'struct s'} } */
+ ue_ptr1 = &s; /* { dg-error {assignment to 'user_enum_ptr' {aka 'enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ ue_ptr2 = &s; /* { dg-error {assignment to 'user_enum \*' {aka 'enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ const_ue_ptr1 = &s; /* { dg-error {assignment to 'const user_enum \*' {aka 'const enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ const_ue_ptr2 = &s; /* { dg-error {assignment to 'const user_enum_copy \*' {aka 'const enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ volatile_ue_ptr1 = &s; /* { dg-error {assignment to 'volatile user_enum \*' {aka 'volatile enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ volatile_ue_ptr2 = &s; /* { dg-error {assignment to 'volatile user_enum_copy \*' {aka 'volatile enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ atomic_ue_ptr1 = &s; /* { dg-error {assignment to '_Atomic user_enum \*' {aka '_Atomic enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ atomic_ue_ptr2 = &s; /* { dg-error {assignment to '_Atomic user_enum_copy \*' {aka '_Atomic enum __internal_enum \*'} from incompatible pointer type 'struct s \*'} } */
+ ue_array_ptr1 = &s; /* { dg-error {assignment to 'user_enum \(\*\)\[10\]' {aka 'enum __internal_enum \(\*\)\[10\]'} from incompatible pointer type 'struct s \*'} } */
+ ue_array_ptr2 = &s; /* { dg-error {assignment to 'user_enum_copy \(\*\)\[10\]' {aka 'enum __internal_enum \(\*\)\[10\]'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr1 = &s; /* { dg-error {assignment to 'user_enum \(\*\)\(void\)' {aka 'enum __internal_enum \(\*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr2 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum\)' {aka 'void \(\*\)\(enum __internal_enum\)'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr3 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum, \.\.\.\)' {aka 'void \(\*\)\(enum __internal_enum, \.\.\.\)'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr4 = &s; /* { dg-error {assignment to 'user_enum_copy \(\*\)\(void\)' {aka 'enum __internal_enum \(\*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr5 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum_copy\)' {aka 'void \(\*\)\(enum __internal_enum\)'} from incompatible pointer type 'struct s \*'} } */
+ ue_fn_ptr6 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_enum_copy, \.\.\.\)' {aka 'void \(\*\)\(enum __internal_enum, \.\.\.\)'} from incompatible pointer type 'struct s \*'} } */
+ unsafe_ue_fn_ptr1 = &s; /* { dg-error {assignment to 'user_enum \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' {aka 'enum __internal_enum \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ unsafe_ue_fn_ptr2 = &s; /* { dg-error {assignment to 'user_enum_copy \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' {aka 'enum __internal_enum \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+
+ us1 = s; /* { dg-error {assigning to type 'user_struct' {aka 'struct __internal_struct'} from type 'struct s'} } */
+ us2 = s; /* { dg-error {assigning to type 'user_struct_copy' {aka 'struct __internal_struct'} from type 'struct s'} } */
+ us_ptr1 = &s; /* { dg-error {assignment to 'user_struct_ptr' {aka 'struct __internal_struct \*'} from incompatible pointer type 'struct s \*'} } */
+ us_ptr2 = &s; /* { dg-error {assignment to 'user_struct \*' {aka 'struct __internal_struct \*'} from incompatible pointer type 'struct s \*'} } */
+ const_us_ptr1 = &s; /* { dg-error {assignment to 'const user_struct \*' {aka 'const struct __internal_struct \*'} from incompatible pointer type 'struct s \*'} } */
+ const_us_ptr2 = &s; /* { dg-error {assignment to 'const user_struct_copy \*' {aka 'const struct __internal_struct \*'} from incompatible pointer type 'struct s \*'} } */
+
+ uu1 = s; /* { dg-error {assigning to type 'user_union' {aka 'union __internal_union'} from type 'struct s'} } */
+ uu2 = s; /* { dg-error {assigning to type 'user_union_copy' {aka 'union __internal_union'} from type 'struct s'} } */
+ uu_ptr1 = &s; /* { dg-error {assignment to 'user_union_ptr' {aka 'union __internal_union \*'} from incompatible pointer type 'struct s \*'} } */
+ uu_ptr2 = &s; /* { dg-error {assignment to 'user_union \*' {aka 'union __internal_union \*'} from incompatible pointer type 'struct s \*'} } */
+ const_uu_ptr1 = &s; /* { dg-error {assignment to 'const user_union \*' {aka 'const union __internal_union \*'} from incompatible pointer type 'struct s \*'} } */
+ const_uu_ptr2 = &s; /* { dg-error {assignment to 'const user_union_copy \*' {aka 'const union __internal_union \*'} from incompatible pointer type 'struct s \*'} } */
+
+ uv1 = s; /* { dg-error {assigning to type 'user_vector' {aka '__vector\([48]\) unsigned int'} from type 'struct s'} } */
+ uv2 = s; /* { dg-error {assigning to type 'user_vector_copy' {aka '__vector\([48]\) unsigned int'} from type 'struct s'} } */
+ uv_ptr1 = &s; /* { dg-error {assignment to 'user_vector_ptr' {aka '__vector\([48]\) unsigned int \*'} from incompatible pointer type 'struct s \*'} } */
+ uv_ptr2 = &s; /* { dg-error {assignment to 'user_vector \*' {aka '__vector\([48]\) unsigned int \*'} from incompatible pointer type 'struct s \*'} } */
+ const_uv_ptr1 = &s; /* { dg-error {assignment to 'const user_vector \*' {aka 'const __vector\([48]\) unsigned int \*'} from incompatible pointer type 'struct s \*'} } */
+ const_uv_ptr2 = &s; /* { dg-error {assignment to 'const user_vector_copy \*' {aka 'const __vector\([48]\) unsigned int \*'} from incompatible pointer type 'struct s \*'} } */
+
+ ui1 = s; /* { dg-error {assigning to type 'user_int' {aka 'int'} from type 'struct s'} } */
+ ui2 = s; /* { dg-error {assigning to type 'user_int_copy' {aka 'int'} from type 'struct s'} } */
+ ui_ptr1 = &s; /* { dg-error {assignment to 'user_int_ptr' {aka 'int \*'} from incompatible pointer type 'struct s \*'} } */
+ ui_ptr2 = &s; /* { dg-error {assignment to 'user_int \*' {aka 'int \*'} from incompatible pointer type 'struct s \*'} } */
+ const_ui_ptr1 = &s; /* { dg-error {assignment to 'const user_int \*' {aka 'const int \*'} from incompatible pointer type 'struct s \*'} } */
+ const_ui_ptr2 = &s; /* { dg-error {assignment to 'const user_int_copy \*' {aka 'const int \*'} from incompatible pointer type 'struct s \*'} } */
+ volatile_ui_ptr1 = &s; /* { dg-error {assignment to 'volatile user_int \*' {aka 'volatile int \*'} from incompatible pointer type 'struct s \*'} } */
+ volatile_ui_ptr2 = &s; /* { dg-error {assignment to 'volatile user_int_copy \*' {aka 'volatile int \*'} from incompatible pointer type 'struct s \*'} } */
+ atomic_ui_ptr1 = &s; /* { dg-error {assignment to '_Atomic user_int \*' {aka '_Atomic int \*'} from incompatible pointer type 'struct s \*'} } */
+ atomic_ui_ptr2 = &s; /* { dg-error {assignment to '_Atomic user_int_copy \*' {aka '_Atomic int \*'} from incompatible pointer type 'struct s \*'} } */
+ ui_array_ptr1 = &s; /* { dg-error {assignment to 'user_int \(\*\)\[10\]' {aka 'int \(\*\)\[10\]'} from incompatible pointer type 'struct s \*'} } */
+ ui_array_ptr2 = &s; /* { dg-error {assignment to 'user_int_copy \(\*\)\[10\]' {aka 'int \(\*\)\[10\]'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr1 = &s; /* { dg-error {assignment to 'user_int \(\*\)\(void\)' {aka 'int \(\*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr2 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int\)' {aka 'void \(\*\)\(int\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr3 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int, \.\.\.\)' {aka 'void \(\*\)\(int, \.\.\.\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr4 = &s; /* { dg-error {assignment to 'user_int_copy \(\*\)\(void\)' {aka 'int \(\*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr5 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int_copy\)' {aka 'void \(\*\)\(int\)'} from incompatible pointer type 'struct s \*'} } */
+ ui_fn_ptr6 = &s; /* { dg-error {assignment to 'void \(\*\)\(user_int_copy, \.\.\.\)' {aka 'void \(\*\)\(int, \.\.\.\)'} from incompatible pointer type 'struct s \*'} } */
+ unsafe_ui_fn_ptr1 = &s; /* { dg-error {assignment to 'user_int \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' {aka 'int \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+ unsafe_ui_fn_ptr2 = &s; /* { dg-error {assignment to 'user_int_copy \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)' {aka 'int \(__attribute__\(\(transaction_unsafe\)\) \*\)\(void\)'} from incompatible pointer type 'struct s \*'} } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/diag_aka_1.c b/gcc/testsuite/gcc.target/aarch64/diag_aka_1.c
index 59e24f4..98dffea 100644
--- a/gcc/testsuite/gcc.target/aarch64/diag_aka_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/diag_aka_1.c
@@ -8,7 +8,6 @@ void f (float x)
__Int8x8_t *ptr1 = &x; /* { dg-error {initialization of '__Int8x8_t \*' from incompatible pointer type 'float \*'} } */
int8x8_t y2 = x; /* { dg-error {incompatible types when initializing type 'int8x8_t' using type 'float'} } */
int8x8_t *ptr2 = &x; /* { dg-error {initialization of 'int8x8_t \*' from incompatible pointer type 'float \*'} } */
- /* ??? For these it would be better to print an aka for 'int16x4_t'. */
- myvec y3 = x; /* { dg-error {incompatible types when initializing type 'myvec' using type 'float'} } */
- myvec *ptr3 = &x; /* { dg-error {initialization of 'myvec \*' from incompatible pointer type 'float \*'} } */
+ myvec y3 = x; /* { dg-error {incompatible types when initializing type 'myvec' {aka 'int16x4_t'} using type 'float'} } */
+ myvec *ptr3 = &x; /* { dg-error {initialization of 'myvec \*' {aka 'int16x4_t \*'} from incompatible pointer type 'float \*'} } */
}