[C] Avoid exposing internal details in aka types
authorRichard Sandiford <richard.sandiford@arm.com>
Mon, 14 Oct 2019 08:05:52 +0000 (08:05 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Mon, 14 Oct 2019 08:05:52 +0000 (08:05 +0000)
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

gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c/ChangeLog
gcc/c/c-objc-common.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/diag-aka-5.h [new file with mode: 0644]
gcc/testsuite/gcc.dg/diag-aka-5a.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/diag-aka-5b.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/diag_aka_1.c

index 2b63689bc7a778e3a96d5ab823af4e6f0db08bef..cb3b9cfa98ef38637a9eb889122002a322ed10e4 100644 (file)
@@ -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,
index 909f52a922a524731925f5ba1d13732a1efb9fb2..483d874bc3a2148830bbd835c03b2b7608885b21 100644 (file)
@@ -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
index db7f26eec5350590d13b5c5c7f8f72345141c28c..3bc021b65d96321a2a2a6769d2ba7695945e5447 100644 (file)
@@ -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> *);
index c76baf060a746192e880916447f286c58850b844..23310ce0e43aa4faa6af62c1830d6b55addb1c7f 100644 (file)
@@ -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
index e1f3b2ee436ccfc53905d1ff361b3ba3b6f2fef7..10d72c57dfb829d4395e3516fccc1657aaa7e0e0 100644 (file)
@@ -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);
index 5db77a788d5e00ea982fbb7f87139e9f2290fcc2..7385c3345055311ac9806215cddc830945b1c0a1 100644 (file)
@@ -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 (file)
index 0000000..0c7404d
--- /dev/null
@@ -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 (file)
index 0000000..8768a79
--- /dev/null
@@ -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 (file)
index 0000000..e0ec7c8
--- /dev/null
@@ -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 \*'} } */
+}
index 59e24f48bd582662d9a32c86853f209be66c185e..98dffead6a8f3a31b54fa7d01eda6ae349f1f235 100644 (file)
@@ -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 \*'} } */
 }