Ping: [C][C++] Avoid exposing internal details in aka types

Jason Merrill jason@redhat.com
Mon Oct 21 19:51:00 GMT 2019


On 10/11/19 10:17 AM, Richard Sandiford wrote:
> Richard Sandiford <richard.sandiford@arm.com> writes:
>> Marek Polacek <polacek@redhat.com> writes:
>>> On Thu, Oct 10, 2019 at 08:00:53PM +0100, Richard Sandiford wrote:
>>>> Ping
>>>>
>>>> Richard Sandiford <richard.sandiford@arm.com> writes:
>>>>> 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.
>>>
>>> Agreed.
>>>
>>>> +/* 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;
>>>
>>> This looks like name_reserved_for_implementation_p.
>>>
>>> The rest looks fine to me!
>>
>> Ah, nice!  I'd looked for a helper but missed that one.
>>
>> Here's just the C parts, with that change.
> 
> And here are the C++ parts, on top of that.  I should probably have
> split them from the outset.
> 
> Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?

OK.

Jason
> 
> Richard
> 
> [Comment from the original covering note, in case it helps:
> 
> 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.]
> 
> 2019-10-11  Richard Sandiford  <richard.sandiford@arm.com>
> 
> 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.
> 
> Index: gcc/cp/cp-tree.h
> ===================================================================
> --- gcc/cp/cp-tree.h	2019-10-08 09:23:43.000000000 +0100
> +++ gcc/cp/cp-tree.h	2019-10-11 15:12:12.544911643 +0100
> @@ -5696,6 +5696,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)	\
> @@ -7254,8 +7261,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-10-08 09:23:43.000000000 +0100
> +++ gcc/cp/tree.c	2019-10-11 15:12:12.544911643 +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-10-08 09:23:43.000000000 +0100
> +++ gcc/cp/error.c	2019-10-11 15:12:12.544911643 +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-10-11 15:12:12.544911643 +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-10-11 15:12:12.544911643 +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-10-11 15:12:12.544911643 +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-10-11 15:12:12.544911643 +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} }
> +}
> 



More information about the Gcc-patches mailing list