On Mon, Sep 30, 2019 at 3:21 PM Richard Sandiford
<richard.sandif...@arm.com> wrote:
>
> 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 C side does this by recursively looking for the aka type, like the
> C++ side 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.
>
> On the C++ side, strip_typedefs had:
>
>           /* Explicitly get the underlying type, as TYPE_MAIN_VARIANT doesn't
>              strip typedefs with attributes.  */
>           result = TYPE_MAIN_VARIANT (DECL_ORIGINAL_TYPE (TYPE_NAME (t)));
>           result = strip_typedefs (result);
>
> Applying TYPE_MAIN_VARIANT predates the strip_typedefs call, with the
> comment originally contrasting with plain:
>
>           result = TYPE_MAIN_VARIANT (t);
>
> But the recursive call to strip_typedefs will apply TYPE_MAIN_VARIANT,
> so it doesn't seem necessary to do it here too.  I think there was also
> a missing "remove_attributes" argument, since wrapping something in a
> typedef shouldn't change which attributes get removed.
>
> Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?

In other context (debug-info) we also look at DECL_ARTIFICIAL,
not sure if that is set on compiler-generated TYPE_DECLs.

> Richard
>
>
> 2019-09-30  Richard Sandiford  <richard.sandif...@arm.com>
>
> gcc/c-family/
>         * c-common.h (user_facing_original_type_p): Declare.
>         * c-common.c (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/cp/
>         * cp-tree.h (STF_USER_VISIBLE): New constant.
>         (strip_typedefs, strip_typedefs_expr): Take a flags argument.
>         * tree.c (strip_typedefs, strip_typedefs_expr): Likewise,
>         updating mutual calls accordingly.  When STF_USER_VISIBLE is true,
>         only look through typedefs if user_facing_original_type_p.
>         * error.c (dump_template_bindings, type_to_string): Pass
>         STF_USER_VISIBLE to strip_typedefs.
>         (dump_type): Likewise, unless pp_c_flag_gnu_v3 is set.
>
> gcc/testsuite/
>         * g++.dg/diagnostic/aka5.h: New test.
>         * g++.dg/diagnostic/aka5a.C: Likewise.
>         * g++.dg/diagnostic/aka5b.C: Likewise.
>         * g++.target/aarch64/diag_aka_1.C: Likewise.
>         * gcc.dg/diag-aka-5.h: Likewise.
>         * 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.
>
> Index: gcc/c-family/c-common.h
> ===================================================================
> --- gcc/c-family/c-common.h     2019-09-30 13:54:16.000000000 +0100
> +++ gcc/c-family/c-common.h     2019-09-30 14:16:45.002103890 +0100
> @@ -1063,6 +1063,7 @@ extern tree builtin_type_for_size (int,
>  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: gcc/c-family/c-common.c
> ===================================================================
> --- gcc/c-family/c-common.c     2019-09-30 13:54:16.000000000 +0100
> +++ gcc/c-family/c-common.c     2019-09-30 14:16:45.002103890 +0100
> @@ -7713,6 +7713,55 @@ 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))
> +    {
> +      const char *name = IDENTIFIER_POINTER (orig_id);
> +      if (name[0] != '_' || (name[1] != '_' && !ISUPPER (name[1])))
> +       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: gcc/c/c-objc-common.c
> ===================================================================
> --- gcc/c/c-objc-common.c       2019-09-30 14:08:26.597671509 +0100
> +++ gcc/c/c-objc-common.c       2019-09-30 14:16:45.002103890 +0100
> @@ -28,6 +28,8 @@ Software Foundation; either version 3, o
>  #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
>       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
>        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: gcc/cp/cp-tree.h
> ===================================================================
> --- gcc/cp/cp-tree.h    2019-09-30 13:54:16.000000000 +0100
> +++ gcc/cp/cp-tree.h    2019-09-30 14:16:45.006103863 +0100
> @@ -5672,6 +5672,13 @@ #define TFF_NO_OMIT_DEFAULT_TEMPLATE_ARG
>  #define TFF_NO_TEMPLATE_BINDINGS               (1 << 13)
>  #define TFF_POINTER                            (1 << 14)
>
> +/* These constants can be used as bit flags to control strip_typedefs.
> +
> +   STF_USER_VISIBLE: use heuristics to try to avoid stripping user-facing
> +       aliases of internal details.  This is intended for diagnostics,
> +       where it should (for example) give more useful "aka" types.  */
> +const unsigned int STF_USER_VISIBLE = 1U;
> +
>  /* Returns the TEMPLATE_DECL associated to a TEMPLATE_TEMPLATE_PARM
>     node.  */
>  #define TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL(NODE)     \
> @@ -7228,8 +7235,10 @@ extern int zero_init_p                           
> (const_tree);
>  extern bool check_abi_tag_redeclaration                (const_tree, 
> const_tree,
>                                                  const_tree);
>  extern bool check_abi_tag_args                 (tree, tree);
> -extern tree strip_typedefs                     (tree, bool * = NULL);
> -extern tree strip_typedefs_expr                        (tree, bool * = NULL);
> +extern tree strip_typedefs                     (tree, bool * = NULL,
> +                                                unsigned int = 0);
> +extern tree strip_typedefs_expr                        (tree, bool * = NULL,
> +                                                unsigned int = 0);
>  extern tree copy_binfo                         (tree, tree, tree,
>                                                  tree *, int);
>  extern int member_p                            (const_tree);
> Index: gcc/cp/tree.c
> ===================================================================
> --- gcc/cp/tree.c       2019-09-30 13:54:16.000000000 +0100
> +++ gcc/cp/tree.c       2019-09-30 14:16:45.006103863 +0100
> @@ -1431,7 +1431,10 @@ apply_identity_attributes (tree result,
>    return cp_build_type_attribute_variant (result, new_attribs);
>  }
>
> -/* Builds a qualified variant of T that is not a typedef variant.
> +/* Builds a qualified variant of T that is either not a typedef variant
> +   (the default behavior) or not a typedef variant of a user-facing type
> +   (if FLAGS contains STF_USER_FACING).
> +
>     E.g. consider the following declarations:
>       typedef const int ConstInt;
>       typedef ConstInt* PtrConstInt;
> @@ -1456,7 +1459,7 @@ apply_identity_attributes (tree result,
>     stripped.  */
>
>  tree
> -strip_typedefs (tree t, bool *remove_attributes)
> +strip_typedefs (tree t, bool *remove_attributes, unsigned int flags)
>  {
>    tree result = NULL, type = NULL, t0 = NULL;
>
> @@ -1471,7 +1474,7 @@ strip_typedefs (tree t, bool *remove_att
>        for (; t; t = TREE_CHAIN (t))
>         {
>           gcc_assert (!TREE_PURPOSE (t));
> -         tree elt = strip_typedefs (TREE_VALUE (t), remove_attributes);
> +         tree elt = strip_typedefs (TREE_VALUE (t), remove_attributes, 
> flags);
>           if (elt != TREE_VALUE (t))
>             changed = true;
>           vec_safe_push (vec, elt);
> @@ -1494,28 +1497,29 @@ strip_typedefs (tree t, bool *remove_att
>    switch (TREE_CODE (t))
>      {
>      case POINTER_TYPE:
> -      type = strip_typedefs (TREE_TYPE (t), remove_attributes);
> +      type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags);
>        result = build_pointer_type (type);
>        break;
>      case REFERENCE_TYPE:
> -      type = strip_typedefs (TREE_TYPE (t), remove_attributes);
> +      type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags);
>        result = cp_build_reference_type (type, TYPE_REF_IS_RVALUE (t));
>        break;
>      case OFFSET_TYPE:
> -      t0 = strip_typedefs (TYPE_OFFSET_BASETYPE (t), remove_attributes);
> -      type = strip_typedefs (TREE_TYPE (t), remove_attributes);
> +      t0 = strip_typedefs (TYPE_OFFSET_BASETYPE (t), remove_attributes, 
> flags);
> +      type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags);
>        result = build_offset_type (t0, type);
>        break;
>      case RECORD_TYPE:
>        if (TYPE_PTRMEMFUNC_P (t))
>         {
> -         t0 = strip_typedefs (TYPE_PTRMEMFUNC_FN_TYPE (t), 
> remove_attributes);
> +         t0 = strip_typedefs (TYPE_PTRMEMFUNC_FN_TYPE (t),
> +                              remove_attributes, flags);
>           result = build_ptrmemfunc_type (t0);
>         }
>        break;
>      case ARRAY_TYPE:
> -      type = strip_typedefs (TREE_TYPE (t), remove_attributes);
> -      t0  = strip_typedefs (TYPE_DOMAIN (t), remove_attributes);
> +      type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags);
> +      t0  = strip_typedefs (TYPE_DOMAIN (t), remove_attributes, flags);
>        result = build_cplus_array_type (type, t0);
>        break;
>      case FUNCTION_TYPE:
> @@ -1534,7 +1538,7 @@ strip_typedefs (tree t, bool *remove_att
>             && (TYPE_ATTRIBUTES (t) || TYPE_USER_ALIGN (t)))
>           is_variant = true;
>
> -       type = strip_typedefs (TREE_TYPE (t), remove_attributes);
> +       type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags);
>         tree canon_spec = (flag_noexcept_type
>                            ? canonical_eh_spec (TYPE_RAISES_EXCEPTIONS (t))
>                            : NULL_TREE);
> @@ -1548,7 +1552,7 @@ strip_typedefs (tree t, bool *remove_att
>             if (arg_node == void_list_node)
>               break;
>             arg_type = strip_typedefs (TREE_VALUE (arg_node),
> -                                      remove_attributes);
> +                                      remove_attributes, flags);
>             gcc_assert (arg_type);
>             if (arg_type == TREE_VALUE (arg_node) && !changed)
>               continue;
> @@ -1612,9 +1616,10 @@ strip_typedefs (tree t, bool *remove_att
>                 tree arg = TREE_VEC_ELT (args, i);
>                 tree strip_arg;
>                 if (TYPE_P (arg))
> -                 strip_arg = strip_typedefs (arg, remove_attributes);
> +                 strip_arg = strip_typedefs (arg, remove_attributes, flags);
>                 else
> -                 strip_arg = strip_typedefs_expr (arg, remove_attributes);
> +                 strip_arg = strip_typedefs_expr (arg, remove_attributes,
> +                                                  flags);
>                 TREE_VEC_ELT (new_args, i) = strip_arg;
>                 if (strip_arg != arg)
>                   changed = true;
> @@ -1630,7 +1635,7 @@ strip_typedefs (tree t, bool *remove_att
>             else
>               ggc_free (new_args);
>           }
> -       tree ctx = strip_typedefs (TYPE_CONTEXT (t), remove_attributes);
> +       tree ctx = strip_typedefs (TYPE_CONTEXT (t), remove_attributes, 
> flags);
>         if (!changed && ctx == TYPE_CONTEXT (t) && !typedef_variant_p (t))
>           return t;
>         tree name = fullname;
> @@ -1643,7 +1648,7 @@ strip_typedefs (tree t, bool *remove_att
>        break;
>      case DECLTYPE_TYPE:
>        result = strip_typedefs_expr (DECLTYPE_TYPE_EXPR (t),
> -                                   remove_attributes);
> +                                   remove_attributes, flags);
>        if (result == DECLTYPE_TYPE_EXPR (t))
>         result = NULL_TREE;
>        else
> @@ -1653,7 +1658,8 @@ strip_typedefs (tree t, bool *remove_att
>                    tf_none));
>        break;
>      case UNDERLYING_TYPE:
> -      type = strip_typedefs (UNDERLYING_TYPE_TYPE (t), remove_attributes);
> +      type = strip_typedefs (UNDERLYING_TYPE_TYPE (t),
> +                            remove_attributes, flags);
>        result = finish_underlying_type (type);
>        break;
>      default:
> @@ -1664,15 +1670,18 @@ strip_typedefs (tree t, bool *remove_att
>      {
>        if (typedef_variant_p (t))
>         {
> -         /* Explicitly get the underlying type, as TYPE_MAIN_VARIANT doesn't
> -            strip typedefs with attributes.  */
> -         result = TYPE_MAIN_VARIANT (DECL_ORIGINAL_TYPE (TYPE_NAME (t)));
> -         result = strip_typedefs (result);
> +         if ((flags & STF_USER_VISIBLE)
> +             && !user_facing_original_type_p (t))
> +           return t;
> +         result = strip_typedefs (DECL_ORIGINAL_TYPE (TYPE_NAME (t)),
> +                                  remove_attributes, flags);
>         }
>        else
>         result = TYPE_MAIN_VARIANT (t);
>      }
> -  gcc_assert (!typedef_variant_p (result));
> +  gcc_assert (!typedef_variant_p (result)
> +             || ((flags & STF_USER_VISIBLE)
> +                 && !user_facing_original_type_p (result)));
>
>    if (COMPLETE_TYPE_P (result) && !COMPLETE_TYPE_P (t))
>    /* If RESULT is complete and T isn't, it's likely the case that T
> @@ -1721,7 +1730,7 @@ strip_typedefs (tree t, bool *remove_att
>     sizeof(TT) is replaced by sizeof(T).  */
>
>  tree
> -strip_typedefs_expr (tree t, bool *remove_attributes)
> +strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags)
>  {
>    unsigned i,n;
>    tree r, type, *ops;
> @@ -1738,7 +1747,7 @@ strip_typedefs_expr (tree t, bool *remov
>    /* Some expressions have type operands, so let's handle types here rather
>       than check TYPE_P in multiple places below.  */
>    if (TYPE_P (t))
> -    return strip_typedefs (t, remove_attributes);
> +    return strip_typedefs (t, remove_attributes, flags);
>
>    code = TREE_CODE (t);
>    switch (code)
> @@ -1752,8 +1761,10 @@ strip_typedefs_expr (tree t, bool *remov
>
>      case TRAIT_EXPR:
>        {
> -       tree type1 = strip_typedefs (TRAIT_EXPR_TYPE1 (t), remove_attributes);
> -       tree type2 = strip_typedefs (TRAIT_EXPR_TYPE2 (t), remove_attributes);
> +       tree type1 = strip_typedefs (TRAIT_EXPR_TYPE1 (t),
> +                                    remove_attributes, flags);
> +       tree type2 = strip_typedefs (TRAIT_EXPR_TYPE2 (t),
> +                                    remove_attributes, flags);
>         if (type1 == TRAIT_EXPR_TYPE1 (t)
>             && type2 == TRAIT_EXPR_TYPE2 (t))
>           return t;
> @@ -1770,7 +1781,8 @@ strip_typedefs_expr (tree t, bool *remov
>         tree it;
>         for (it = t; it; it = TREE_CHAIN (it))
>           {
> -           tree val = strip_typedefs_expr (TREE_VALUE (it), 
> remove_attributes);
> +           tree val = strip_typedefs_expr (TREE_VALUE (it),
> +                                           remove_attributes, flags);
>             vec_safe_push (vec, val);
>             if (val != TREE_VALUE (it))
>               changed = true;
> @@ -1796,7 +1808,7 @@ strip_typedefs_expr (tree t, bool *remov
>         for (i = 0; i < n; ++i)
>           {
>             tree op = strip_typedefs_expr (TREE_VEC_ELT (t, i),
> -                                          remove_attributes);
> +                                          remove_attributes, flags);
>             vec->quick_push (op);
>             if (op != TREE_VEC_ELT (t, i))
>               changed = true;
> @@ -1820,18 +1832,19 @@ strip_typedefs_expr (tree t, bool *remov
>         vec<constructor_elt, va_gc> *vec
>           = vec_safe_copy (CONSTRUCTOR_ELTS (t));
>         n = CONSTRUCTOR_NELTS (t);
> -       type = strip_typedefs (TREE_TYPE (t), remove_attributes);
> +       type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags);
>         for (i = 0; i < n; ++i)
>           {
>             constructor_elt *e = &(*vec)[i];
> -           tree op = strip_typedefs_expr (e->value, remove_attributes);
> +           tree op = strip_typedefs_expr (e->value, remove_attributes, 
> flags);
>             if (op != e->value)
>               {
>                 changed = true;
>                 e->value = op;
>               }
>             gcc_checking_assert
> -             (e->index == strip_typedefs_expr (e->index, remove_attributes));
> +             (e->index == strip_typedefs_expr (e->index, remove_attributes,
> +                                               flags));
>           }
>
>         if (!changed && type == TREE_TYPE (t))
> @@ -1875,12 +1888,13 @@ strip_typedefs_expr (tree t, bool *remov
>      case REINTERPRET_CAST_EXPR:
>      case CAST_EXPR:
>      case NEW_EXPR:
> -      type = strip_typedefs (type, remove_attributes);
> +      type = strip_typedefs (type, remove_attributes, flags);
>        /* fallthrough */
>
>      default:
>        for (i = 0; i < n; ++i)
> -       ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i), remove_attributes);
> +       ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i),
> +                                     remove_attributes, flags);
>        break;
>      }
>
> Index: gcc/cp/error.c
> ===================================================================
> --- gcc/cp/error.c      2019-09-30 13:54:16.000000000 +0100
> +++ gcc/cp/error.c      2019-09-30 14:16:45.006103863 +0100
> @@ -409,7 +409,7 @@ dump_template_bindings (cxx_pretty_print
>        pop_deferring_access_checks ();
>        /* Strip typedefs.  We can't just use TFF_CHASE_TYPEDEF because
>          pp_simple_type_specifier doesn't know about it.  */
> -      t = strip_typedefs (t);
> +      t = strip_typedefs (t, NULL, STF_USER_VISIBLE);
>        dump_type (pp, t, TFF_PLAIN_IDENTIFIER);
>      }
>  }
> @@ -448,7 +448,11 @@ dump_type (cxx_pretty_printer *pp, tree
>                || DECL_SELF_REFERENCE_P (decl)
>                || (!flag_pretty_templates
>                    && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)))
> -       t = strip_typedefs (t);
> +       {
> +         unsigned int stf_flags = (!(pp->flags & pp_c_flag_gnu_v3)
> +                                   ? STF_USER_VISIBLE : 0);
> +         t = strip_typedefs (t, NULL, stf_flags);
> +       }
>        else if (alias_template_specialization_p (t))
>         {
>           dump_alias_template_specialization (pp, t, flags);
> @@ -3195,7 +3199,7 @@ type_to_string (tree typ, int verbose, b
>        && !uses_template_parms (typ))
>      {
>        int aka_start, aka_len; char *p;
> -      tree aka = strip_typedefs (typ);
> +      tree aka = strip_typedefs (typ, NULL, STF_USER_VISIBLE);
>        if (quote && *quote)
>         pp_end_quote (cxx_pp, show_color);
>        pp_string (cxx_pp, " {aka");
> Index: gcc/testsuite/g++.dg/diagnostic/aka5.h
> ===================================================================
> --- /dev/null   2019-09-17 11:41:18.176664108 +0100
> +++ gcc/testsuite/g++.dg/diagnostic/aka5.h      2019-09-30 14:16:45.006103863 
> +0100
> @@ -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;
> Index: gcc/testsuite/g++.dg/diagnostic/aka5a.C
> ===================================================================
> --- /dev/null   2019-09-17 11:41:18.176664108 +0100
> +++ gcc/testsuite/g++.dg/diagnostic/aka5a.C     2019-09-30 14:16:45.010103832 
> +0100
> @@ -0,0 +1,127 @@
> +#define IS_SYSTEM_HEADER
> +#include "aka5.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;
> +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;
> +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 (s s1)
> +{
> +  ue1 = s1; // { dg-error {cannot convert 's' to 'user_enum' in assignment} }
> +  ue2 = s1; // { dg-error {cannot convert 's' to 'user_enum_copy' {aka 
> 'user_enum'} in assignment} }
> +  ue_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_enum_ptr' {aka 
> 'user_enum\*'} in assignment} }
> +  ue_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'user_enum\*' in 
> assignment} }
> +  const_ue_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_enum\*' in assignment} }
> +  const_ue_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_enum_copy\*' {aka 'const user_enum\*'} in assignment} }
> +  volatile_ue_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'volatile 
> user_enum\*' in assignment} }
> +  volatile_ue_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'volatile 
> user_enum_copy\*' {aka 'volatile user_enum\*'} in assignment} }
> +  ue_array_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_enum 
> \(\*\)\[10\]' in assignment} }
> +  ue_array_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 
> 'user_enum_copy \(\*\)\[10\]' {aka 'user_enum \(\*\)\[10\]'} in assignment} }
> +  ue_fn_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_enum 
> \(\*\)\(\)' in assignment} }
> +  ue_fn_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_enum\)' in assignment} }
> +  ue_fn_ptr3 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_enum, \.\.\.\)' in assignment} }
> +  ue_fn_ptr4 = &s1; // { dg-error {cannot convert 's\*' to 'user_enum_copy 
> \(\*\)\(\)' {aka 'user_enum \(\*\)\(\)'} in assignment} }
> +  ue_fn_ptr5 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_enum_copy\)' {aka 'void \(\*\)\(user_enum\)'} in assignment} }
> +  ue_fn_ptr6 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_enum_copy, \.\.\.\)' {aka 'void \(\*\)\(user_enum, \.\.\.\)'} in 
> assignment} }
> +  unsafe_ue_fn_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_enum 
> \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)' in assignment} }
> +  unsafe_ue_fn_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 
> 'user_enum_copy \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)' {aka 
> 'user_enum \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)'} in 
> assignment} }
> +
> +  us1 = s1; // { dg-error {no match for 'operator=' in 'us1 = s1' \(operand 
> types are 'user_struct' and 's'\)} }
> +  us2 = s1; // { dg-error {no match for 'operator=' in 'us2 = s1' \(operand 
> types are 'user_struct_copy' {aka 'user_struct'} and 's'\)} }
> +  us_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_struct_ptr' 
> {aka 'user_struct\*'} in assignment} }
> +  us_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'user_struct\*' in 
> assignment} }
> +  const_us_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_struct\*' in assignment} }
> +  const_us_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_struct_copy\*' {aka 'const user_struct\*'} in assignment} }
> +
> +  uu1 = s1; // { dg-error {no match for 'operator=' in 'uu1 = s1' \(operand 
> types are 'user_union' and 's'\)} }
> +  uu2 = s1; // { dg-error {no match for 'operator=' in 'uu2 = s1' \(operand 
> types are 'user_union_copy' {aka 'user_union'} and 's'\)} }
> +  uu_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_union_ptr' 
> {aka 'user_union\*'} in assignment} }
> +  uu_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'user_union\*' in 
> assignment} }
> +  const_uu_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_union\*' in assignment} }
> +  const_uu_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_union_copy\*' {aka 'const user_union\*'} in assignment} }
> +
> +  uv1 = s1; // { dg-error {cannot convert 's' to 'user_vector' in 
> assignment} }
> +  uv2 = s1; // { dg-error {cannot convert 's' to 'user_vector_copy' {aka 
> 'user_vector'} in assignment} }
> +  uv_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_vector_ptr' 
> {aka 'user_vector\*'} in assignment} }
> +  uv_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'user_vector\*' in 
> assignment} }
> +  const_uv_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_vector\*' in assignment} }
> +  const_uv_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_vector_copy\*' {aka 'const user_vector\*'} in assignment} }
> +
> +  ui1 = s1; // { dg-error {cannot convert 's' to 'user_int' {aka 'int'} in 
> assignment} }
> +  ui2 = s1; // { dg-error {cannot convert 's' to 'user_int_copy' {aka 'int'} 
> in assignment} }
> +  ui_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_int_ptr' {aka 
> 'int\*'} in assignment} }
> +  ui_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'user_int\*' {aka 
> 'int\*'} in assignment} }
> +  const_ui_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_int\*' {aka 'const int\*'} in assignment} }
> +  const_ui_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_int_copy\*' {aka 'const int\*'} in assignment} }
> +  volatile_ui_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'volatile 
> user_int\*' {aka 'volatile int\*'} in assignment} }
> +  volatile_ui_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'volatile 
> user_int_copy\*' {aka 'volatile int\*'} in assignment} }
> +  ui_array_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_int 
> \(\*\)\[10\]' {aka 'int \(\*\)\[10\]'} in assignment} }
> +  ui_array_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'user_int_copy 
> \(\*\)\[10\]' {aka 'int \(\*\)\[10\]'} in assignment} }
> +  ui_fn_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_int 
> \(\*\)\(\)' {aka 'int \(\*\)\(\)'} in assignment} }
> +  ui_fn_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_int\)' {aka 'void \(\*\)\(int\)'} in assignment} }
> +  ui_fn_ptr3 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_int, \.\.\.\)' {aka 'void \(\*\)\(int, \.\.\.\)'} in assignment} 
> }
> +  ui_fn_ptr4 = &s1; // { dg-error {cannot convert 's\*' to 'user_int_copy 
> \(\*\)\(\)' {aka 'int \(\*\)\(\)'} in assignment} }
> +  ui_fn_ptr5 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_int_copy\)' {aka 'void \(\*\)\(int\)'} in assignment} }
> +  ui_fn_ptr6 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_int_copy, \.\.\.\)' {aka 'void \(\*\)\(int, \.\.\.\)'} in 
> assignment} }
> +  unsafe_ui_fn_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_int 
> \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)' {aka 'int 
> \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)'} in assignment} }
> +  unsafe_ui_fn_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 
> 'user_int_copy \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)' {aka 'int 
> \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)'} in assignment} }
> +}
> Index: gcc/testsuite/g++.dg/diagnostic/aka5b.C
> ===================================================================
> --- /dev/null   2019-09-17 11:41:18.176664108 +0100
> +++ gcc/testsuite/g++.dg/diagnostic/aka5b.C     2019-09-30 14:16:45.010103832 
> +0100
> @@ -0,0 +1,127 @@
> +#include "aka5.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;
> +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;
> +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 (s s1)
> +{
> +  ue1 = s1; // { dg-error {cannot convert 's' to 'user_enum' {aka 
> '__internal_enum'} in assignment} }
> +  ue2 = s1; // { dg-error {cannot convert 's' to 'user_enum_copy' {aka 
> '__internal_enum'} in assignment} }
> +  ue_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_enum_ptr' {aka 
> '__internal_enum\*'} in assignment} }
> +  ue_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'user_enum\*' {aka 
> '__internal_enum\*'} in assignment} }
> +  const_ue_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_enum\*' {aka 'const __internal_enum\*'} in assignment} }
> +  const_ue_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_enum_copy\*' {aka 'const __internal_enum\*'} in assignment} }
> +  volatile_ue_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'volatile 
> user_enum\*' {aka 'volatile __internal_enum\*'} in assignment} }
> +  volatile_ue_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'volatile 
> user_enum_copy\*' {aka 'volatile __internal_enum\*'} in assignment} }
> +  ue_array_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_enum 
> \(\*\)\[10\]' {aka '__internal_enum \(\*\)\[10\]'} in assignment} }
> +  ue_array_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 
> 'user_enum_copy \(\*\)\[10\]' {aka '__internal_enum \(\*\)\[10\]'} in 
> assignment} }
> +  ue_fn_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_enum 
> \(\*\)\(\)' {aka '__internal_enum \(\*\)\(\)'} in assignment} }
> +  ue_fn_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_enum\)' {aka 'void \(\*\)\(__internal_enum\)'} in assignment} }
> +  ue_fn_ptr3 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_enum, \.\.\.\)' {aka 'void \(\*\)\(__internal_enum, \.\.\.\)'} 
> in assignment} }
> +  ue_fn_ptr4 = &s1; // { dg-error {cannot convert 's\*' to 'user_enum_copy 
> \(\*\)\(\)' {aka '__internal_enum \(\*\)\(\)'} in assignment} }
> +  ue_fn_ptr5 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_enum_copy\)' {aka 'void \(\*\)\(__internal_enum\)'} in 
> assignment} }
> +  ue_fn_ptr6 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_enum_copy, \.\.\.\)' {aka 'void \(\*\)\(__internal_enum, 
> \.\.\.\)'} in assignment} }
> +  unsafe_ue_fn_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_enum 
> \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)' {aka '__internal_enum 
> \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)'} in assignment} }
> +  unsafe_ue_fn_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 
> 'user_enum_copy \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)' {aka 
> '__internal_enum \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)'} in 
> assignment} }
> +
> +  us1 = s1; // { dg-error {no match for 'operator=' in 'us1 = s1' \(operand 
> types are 'user_struct' {aka '__internal_struct'} and 's'\)} }
> +  us2 = s1; // { dg-error {no match for 'operator=' in 'us2 = s1' \(operand 
> types are 'user_struct_copy' {aka '__internal_struct'} and 's'\)} }
> +  us_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_struct_ptr' 
> {aka '__internal_struct\*'} in assignment} }
> +  us_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'user_struct\*' {aka 
> '__internal_struct\*'} in assignment} }
> +  const_us_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_struct\*' {aka 'const __internal_struct\*'} in assignment} }
> +  const_us_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_struct_copy\*' {aka 'const __internal_struct\*'} in assignment} }
> +
> +  uu1 = s1; // { dg-error {no match for 'operator=' in 'uu1 = s1' \(operand 
> types are 'user_union' {aka '__internal_union'} and 's'\)} }
> +  uu2 = s1; // { dg-error {no match for 'operator=' in 'uu2 = s1' \(operand 
> types are 'user_union_copy' {aka '__internal_union'} and 's'\)} }
> +  uu_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_union_ptr' 
> {aka '__internal_union\*'} in assignment} }
> +  uu_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'user_union\*' {aka 
> '__internal_union\*'} in assignment} }
> +  const_uu_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_union\*' {aka 'const __internal_union\*'} in assignment} }
> +  const_uu_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_union_copy\*' {aka 'const __internal_union\*'} in assignment} }
> +
> +  uv1 = s1; // { dg-error {cannot convert 's' to 'user_vector' {aka 
> '__vector\([48]\) unsigned int'} in assignment} }
> +  uv2 = s1; // { dg-error {cannot convert 's' to 'user_vector_copy' {aka 
> '__vector\([48]\) unsigned int'} in assignment} }
> +  uv_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_vector_ptr' 
> {aka '__vector\([48]\) unsigned int\*'} in assignment} }
> +  uv_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'user_vector\*' {aka 
> '__vector\([48]\) unsigned int\*'} in assignment} }
> +  const_uv_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_vector\*' {aka 'const __vector\([48]\) unsigned int\*'} in assignment} }
> +  const_uv_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_vector_copy\*' {aka 'const __vector\([48]\) unsigned int\*'} in 
> assignment} }
> +
> +  ui1 = s1; // { dg-error {cannot convert 's' to 'user_int' {aka 'int'} in 
> assignment} }
> +  ui2 = s1; // { dg-error {cannot convert 's' to 'user_int_copy' {aka 'int'} 
> in assignment} }
> +  ui_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_int_ptr' {aka 
> 'int\*'} in assignment} }
> +  ui_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'user_int\*' {aka 
> 'int\*'} in assignment} }
> +  const_ui_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_int\*' {aka 'const int\*'} in assignment} }
> +  const_ui_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'const 
> user_int_copy\*' {aka 'const int\*'} in assignment} }
> +  volatile_ui_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'volatile 
> user_int\*' {aka 'volatile int\*'} in assignment} }
> +  volatile_ui_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'volatile 
> user_int_copy\*' {aka 'volatile int\*'} in assignment} }
> +  ui_array_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_int 
> \(\*\)\[10\]' {aka 'int \(\*\)\[10\]'} in assignment} }
> +  ui_array_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'user_int_copy 
> \(\*\)\[10\]' {aka 'int \(\*\)\[10\]'} in assignment} }
> +  ui_fn_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_int 
> \(\*\)\(\)' {aka 'int \(\*\)\(\)'} in assignment} }
> +  ui_fn_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_int\)' {aka 'void \(\*\)\(int\)'} in assignment} }
> +  ui_fn_ptr3 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_int, \.\.\.\)' {aka 'void \(\*\)\(int, \.\.\.\)'} in assignment} 
> }
> +  ui_fn_ptr4 = &s1; // { dg-error {cannot convert 's\*' to 'user_int_copy 
> \(\*\)\(\)' {aka 'int \(\*\)\(\)'} in assignment} }
> +  ui_fn_ptr5 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_int_copy\)' {aka 'void \(\*\)\(int\)'} in assignment} }
> +  ui_fn_ptr6 = &s1; // { dg-error {cannot convert 's\*' to 'void 
> \(\*\)\(user_int_copy, \.\.\.\)' {aka 'void \(\*\)\(int, \.\.\.\)'} in 
> assignment} }
> +  unsafe_ui_fn_ptr1 = &s1; // { dg-error {cannot convert 's\*' to 'user_int 
> \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)' {aka 'int 
> \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)'} in assignment} }
> +  unsafe_ui_fn_ptr2 = &s1; // { dg-error {cannot convert 's\*' to 
> 'user_int_copy \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)' {aka 'int 
> \(__attribute__\(\(transaction_unsafe\)\) \*\)\(\)'} in assignment} }
> +}
> +
> Index: gcc/testsuite/g++.target/aarch64/diag_aka_1.C
> ===================================================================
> --- /dev/null   2019-09-17 11:41:18.176664108 +0100
> +++ gcc/testsuite/g++.target/aarch64/diag_aka_1.C       2019-09-30 
> 14:16:45.010103832 +0100
> @@ -0,0 +1,13 @@
> +#include <arm_neon.h>
> +
> +typedef int16x4_t myvec;
> +
> +void f (float x)
> +{
> +  __Int8x8_t y1 = x; // { dg-error {cannot convert 'float' to '__Int8x8_t' 
> in initialization} }
> +  __Int8x8_t *ptr1 = &x; // { dg-error {cannot convert 'float\*' to 
> '__Int8x8_t\*' in initialization} }
> +  int8x8_t y2 = x; // { dg-error {cannot convert 'float' to 'int8x8_t' in 
> initialization} }
> +  int8x8_t *ptr2 = &x; // { dg-error {cannot convert 'float\*' to 
> 'int8x8_t\*' in initialization} }
> +  myvec y3 = x; // { dg-error {cannot convert 'float' to 'myvec' {aka 
> 'int16x4_t'} in initialization} }
> +  myvec *ptr3 = &x; // { dg-error {cannot convert 'float\*' to 'myvec\*' 
> {aka 'int16x4_t\*'} in initialization} }
> +}
> Index: gcc/testsuite/gcc.dg/diag-aka-5.h
> ===================================================================
> --- /dev/null   2019-09-17 11:41:18.176664108 +0100
> +++ gcc/testsuite/gcc.dg/diag-aka-5.h   2019-09-30 14:16:45.010103832 +0100
> @@ -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;
> Index: gcc/testsuite/gcc.dg/diag-aka-5a.c
> ===================================================================
> --- /dev/null   2019-09-17 11:41:18.176664108 +0100
> +++ gcc/testsuite/gcc.dg/diag-aka-5a.c  2019-09-30 14:16:45.010103832 +0100
> @@ -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 \*'} } */
> +}
> Index: gcc/testsuite/gcc.dg/diag-aka-5b.c
> ===================================================================
> --- /dev/null   2019-09-17 11:41:18.176664108 +0100
> +++ gcc/testsuite/gcc.dg/diag-aka-5b.c  2019-09-30 14:16:45.010103832 +0100
> @@ -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: gcc/testsuite/gcc.target/aarch64/diag_aka_1.c
> ===================================================================
> --- gcc/testsuite/gcc.target/aarch64/diag_aka_1.c       2019-09-30 
> 14:01:05.908830119 +0100
> +++ gcc/testsuite/gcc.target/aarch64/diag_aka_1.c       2019-09-30 
> 14:16:45.010103832 +0100
> @@ -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 \*'} } */
>  }

Reply via email to