Ping

Richard Sandiford <richard.sandif...@arm.com> writes:
> This patch adds a new target hook to check whether there are any
> target-specific reasons why a type cannot be used in a certain
> source-language context.  It works in a similar way to existing
> hooks like TARGET_INVALID_CONVERSION and TARGET_INVALID_UNARY_OP.
>
> The reason for adding the hook is to report invalid uses of SVE types.
> Throughout a TU, the SVE vector and predicate types represent values
> that can be stored in an SVE vector or predicate register.  At certain
> points in the TU we might be able to generate code that assumes the
> registers have a particular size, but often we can't.  In some cases
> we might even make multiple different assumptions in the same TU
> (e.g. when implementing an ifunc for multiple vector lengths).
>
> But SVE types themselves are the same type throughout.  The register
> size assumptions change how we generate code, but they don't change
> the definition of the types.
>
> This means that the types do not have a fixed size at the C level
> even when -msve-vector-bits=N is in effect.  It also means that the
> size does not work in the same way as for C VLAs, where the abstract
> machine evaluates the size at a particular point and then carries that
> size forward to later code.
>
> The SVE ACLE deals with this by making it invalid to use C and C++
> constructs that depend on the size or layout of SVE types.  The spec
> refers to the types as "sizeless" types and defines their semantics as
> edits to the standards.  See:
>
>   https://gcc.gnu.org/ml/gcc-patches/2018-10/msg00868.html
>
> for a fuller description and:
>
>   https://gcc.gnu.org/ml/gcc/2019-11/msg00088.html
>
> for a recent update on the status.
>
> However, since all current sizeless types are target-specific built-in
> types, there's no real reason for the frontends to handle them directly.
> They can just hand off the checks to target code instead.  It's then
> possible for the errors to refer to "SVE types" rather than "sizeless
> types", which is likely to be more meaningful to users.
>
> There is a slight overlap between the new tests and the ones for
> gnu_vector_type_p in r277950, but here the emphasis is on testing
> sizelessness.
>
> Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?
>
> Richard

2019-11-12  Richard Sandiford  <richard.sandif...@arm.com>

gcc/
        * target.h (type_context_kind): New enum.
        (verify_type_context): Declare.
        * target.def (verify_type_context): New target hook.
        * doc/tm.texi.in (TARGET_VERIFY_TYPE_CONTEXT): Likewise.
        * doc/tm.texi: Regenerate.
        * tree.c (verify_type_context): New function.
        * config/aarch64/aarch64-protos.h (aarch64_sve::verify_type_context):
        Declare.
        * config/aarch64/aarch64-sve-builtins.cc (verify_type_context):
        New function.
        * config/aarch64/aarch64.c (aarch64_verify_type_context): Likewise.
        (TARGET_VERIFY_TYPE_CONTEXT): Define.

gcc/c-family/
        * c-common.c (pointer_int_sum): Use verify_type_context to check
        whether the target allows pointer arithmetic for the types involved.
        (c_sizeof_or_alignof_type, c_alignof_expr): Use verify_type_context
        to check whether the target allows sizeof and alignof operations
        for the types involved.

gcc/c/
        * c-decl.c (start_decl): Allow initialization of variables whose
        size is a POLY_INT_CST.
        (finish_decl): Use verify_type_context to check whether the target
        allows variables with a particular type to have static or thread-local
        storage duration.  Don't raise a second error if such variables do
        not have a constant size.
        (grokdeclarator): Use verify_type_context to check whether the
        target allows fields or array elements to have a particular type.
        * c-typeck.c (pointer_diff): Use verify_type_context to test whether
        the target allows pointer difference for the types involved.
        (build_unary_op): Likewise for pointer increment and decrement.

gcc/testsuite/
        * gcc.target/aarch64/sve/acle/general-c/sizeless-1.c: New test.
        * gcc.target/aarch64/sve/acle/general-c/sizeless-2.c: Likewise.

Index: gcc/target.h
===================================================================
--- gcc/target.h        2019-11-08 08:31:17.000000000 +0000
+++ gcc/target.h        2019-11-12 16:01:45.643584681 +0000
@@ -218,6 +218,35 @@ enum omp_device_kind_arch_isa {
   omp_device_isa
 };
 
+/* The contexts in which the use of a type T can be checked by
+   TARGET_VERIFY_TYPE_CONTEXT.  */
+enum type_context_kind {
+  /* Directly measuring the size of T.  */
+  TCTX_SIZEOF,
+
+  /* Directly measuring the alignment of T.  */
+  TCTX_ALIGNOF,
+
+  /* Creating objects of type T with static storage duration.  */
+  TCTX_STATIC_STORAGE,
+
+  /* Creating objects of type T with thread-local storage duration.  */
+  TCTX_THREAD_STORAGE,
+
+  /* Creating a field of type T.  */
+  TCTX_FIELD,
+
+  /* Creating an array with elements of type T.  */
+  TCTX_ARRAY_ELEMENT,
+
+  /* Adding to or subtracting from a pointer to T, or computing the
+     difference between two pointers when one of them is a pointer to T.  */
+  TCTX_POINTER_ARITH
+};
+
+extern bool verify_type_context (location_t, type_context_kind, const_tree,
+                                bool = false);
+
 /* The target structure.  This holds all the backend hooks.  */
 #define DEFHOOKPOD(NAME, DOC, TYPE, INIT) TYPE NAME;
 #define DEFHOOK(NAME, DOC, TYPE, PARAMS, INIT) TYPE (* NAME) PARAMS;
Index: gcc/target.def
===================================================================
--- gcc/target.def      2019-11-08 08:31:20.000000000 +0000
+++ gcc/target.def      2019-11-12 16:01:45.643584681 +0000
@@ -5258,6 +5258,22 @@ This is currently used only by the C and
  hook_tree_tree_tree_null)
 
 DEFHOOK
+(verify_type_context,
+ "If defined, this hook returns false if there is a target-specific reason\n\
+why type @var{type} cannot be used in the source language context described\n\
+by @var{context}.  When @var{silent_p} is false, the hook also reports an\n\
+error against @var{loc} for invalid uses of @var{type}.\n\
+\n\
+Calls to this hook should be made through the global function\n\
+@code{verify_type_context}, which makes the @var{silent_p} parameter\n\
+default to false and also handles @code{error_mark_node}.\n\
+\n\
+The default implementation always returns true.",
+ bool, (location_t loc, type_context_kind context, const_tree type,
+       bool silent_p),
+ NULL)
+
+DEFHOOK
 (can_change_mode_class,
  "This hook returns true if it is possible to bitcast values held in\n\
 registers of class @var{rclass} from mode @var{from} to mode @var{to}\n\
Index: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in  2019-11-08 08:31:20.000000000 +0000
+++ gcc/doc/tm.texi.in  2019-11-12 16:01:45.643584681 +0000
@@ -8107,6 +8107,8 @@ and scanf formatter settings.
 
 @hook TARGET_CONVERT_TO_TYPE
 
+@hook TARGET_VERIFY_TYPE_CONTEXT
+
 @defmac OBJC_JBLEN
 This macro determines the size of the objective C jump buffer for the
 NeXT runtime. By default, OBJC_JBLEN is defined to an innocuous value.
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi     2019-11-08 08:31:20.000000000 +0000
+++ gcc/doc/tm.texi     2019-11-12 16:01:45.639584709 +0000
@@ -11970,6 +11970,19 @@ conversion rules.
 This is currently used only by the C and C++ front ends.
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_VERIFY_TYPE_CONTEXT (location_t 
@var{loc}, type_context_kind @var{context}, const_tree @var{type}, bool 
@var{silent_p})
+If defined, this hook returns false if there is a target-specific reason
+why type @var{type} cannot be used in the source language context described
+by @var{context}.  When @var{silent_p} is false, the hook also reports an
+error against @var{loc} for invalid uses of @var{type}.
+
+Calls to this hook should be made through the global function
+@code{verify_type_context}, which makes the @var{silent_p} parameter
+default to false and also handles @code{error_mark_node}.
+
+The default implementation always returns true.
+@end deftypefn
+
 @defmac OBJC_JBLEN
 This macro determines the size of the objective C jump buffer for the
 NeXT runtime. By default, OBJC_JBLEN is defined to an innocuous value.
Index: gcc/tree.c
===================================================================
--- gcc/tree.c  2019-11-11 19:43:27.680795692 +0000
+++ gcc/tree.c  2019-11-12 16:01:45.679584431 +0000
@@ -15121,6 +15121,21 @@ max_object_size (void)
   return TYPE_MAX_VALUE (ptrdiff_type_node);
 }
 
+/* A wrapper around TARGET_VERIFY_TYPE_CONTEXT that makes the silent_p
+   parameter default to false and that weeds out error_mark_node.  */
+
+bool
+verify_type_context (location_t loc, type_context_kind context,
+                    const_tree type, bool silent_p)
+{
+  if (type == error_mark_node)
+    return true;
+
+  gcc_assert (TYPE_P (type));
+  return (!targetm.verify_type_context
+         || targetm.verify_type_context (loc, context, type, silent_p));
+}
+
 #if CHECKING_P
 
 namespace selftest {
Index: gcc/config/aarch64/aarch64-protos.h
===================================================================
--- gcc/config/aarch64/aarch64-protos.h 2019-10-29 17:01:12.635889352 +0000
+++ gcc/config/aarch64/aarch64-protos.h 2019-11-12 16:01:45.631584764 +0000
@@ -714,6 +714,9 @@ tree aarch64_builtin_vectorized_function
                           tree, unsigned int, tree *);
   gimple *gimple_fold_builtin (unsigned int, gimple_stmt_iterator *, gcall *);
   rtx expand_builtin (unsigned int, tree, rtx);
+#ifdef GCC_TARGET_H
+  bool verify_type_context (location_t, type_context_kind, const_tree, bool);
+#endif
 }
 
 extern void aarch64_split_combinev16qi (rtx operands[3]);
Index: gcc/config/aarch64/aarch64-sve-builtins.cc
===================================================================
--- gcc/config/aarch64/aarch64-sve-builtins.cc  2019-11-08 08:35:15.576104302 
+0000
+++ gcc/config/aarch64/aarch64-sve-builtins.cc  2019-11-12 16:01:45.631584764 
+0000
@@ -3292,6 +3292,55 @@ builtin_type_p (const_tree type)
   return svbool_type_p (type) || nvectors_if_data_type (type) > 0;
 }
 
+/* Implement TARGET_VERIFY_TYPE_CONTEXT for SVE types.  */
+bool
+verify_type_context (location_t loc, type_context_kind context,
+                    const_tree type, bool silent_p)
+{
+  if (!builtin_type_p (type))
+    return true;
+
+  switch (context)
+    {
+    case TCTX_SIZEOF:
+    case TCTX_STATIC_STORAGE:
+      if (!silent_p)
+       error_at (loc, "SVE type %qT does not have a fixed size", type);
+      return false;
+
+    case TCTX_ALIGNOF:
+      if (!silent_p)
+       error_at (loc, "SVE type %qT does not have a defined alignment", type);
+      return false;
+
+    case TCTX_THREAD_STORAGE:
+      if (!silent_p)
+       error_at (loc, "variables of type %qT cannot have thread-local"
+                 " storage duration", type);
+      return false;
+
+    case TCTX_POINTER_ARITH:
+      if (!silent_p)
+       error_at (loc, "arithmetic on pointer to SVE type %qT", type);
+      return false;
+
+    case TCTX_FIELD:
+      if (silent_p)
+       ;
+      else if (lang_GNU_CXX ())
+       error_at (loc, "member variables cannot have SVE type %qT", type);
+      else
+       error_at (loc, "fields cannot have SVE type %qT", type);
+      return false;
+
+    case TCTX_ARRAY_ELEMENT:
+      if (!silent_p)
+       error_at (loc, "array elements cannot have SVE type %qT", type);
+      return false;
+    }
+  gcc_unreachable ();
+}
+
 }
 
 using namespace aarch64_sve;
Index: gcc/config/aarch64/aarch64.c
===================================================================
--- gcc/config/aarch64/aarch64.c        2019-11-08 08:31:20.000000000 +0000
+++ gcc/config/aarch64/aarch64.c        2019-11-12 16:01:45.635584735 +0000
@@ -15966,6 +15966,15 @@ aarch64_mangle_type (const_tree type)
   return NULL;
 }
 
+/* Implement TARGET_VERIFY_TYPE_CONTEXT.  */
+
+static bool
+aarch64_verify_type_context (location_t loc, type_context_kind context,
+                            const_tree type, bool silent_p)
+{
+  return aarch64_sve::verify_type_context (loc, context, type, silent_p);
+}
+
 /* Find the first rtx_insn before insn that will generate an assembly
    instruction.  */
 
@@ -21621,6 +21630,9 @@ #define TARGET_LIBGCC_FLOATING_MODE_SUPP
 #undef TARGET_MANGLE_TYPE
 #define TARGET_MANGLE_TYPE aarch64_mangle_type
 
+#undef TARGET_VERIFY_TYPE_CONTEXT
+#define TARGET_VERIFY_TYPE_CONTEXT aarch64_verify_type_context
+
 #undef TARGET_MEMORY_MOVE_COST
 #define TARGET_MEMORY_MOVE_COST aarch64_memory_move_cost
 
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c     2019-11-08 08:35:15.572104330 +0000
+++ gcc/c-family/c-common.c     2019-11-12 16:01:45.611584902 +0000
@@ -3143,6 +3143,9 @@ pointer_int_sum (location_t loc, enum tr
        return error_mark_node;
       size_exp = integer_one_node;
     }
+  else if (!verify_type_context (loc, TCTX_POINTER_ARITH,
+                                TREE_TYPE (result_type)))
+    size_exp = integer_one_node;
   else
     size_exp = size_in_bytes_loc (loc, TREE_TYPE (result_type));
 
@@ -3688,6 +3691,13 @@ c_sizeof_or_alignof_type (location_t loc
                  "incomplete element type", op_name, type);
       return error_mark_node;
     }
+  else if (!verify_type_context (loc, is_sizeof ? TCTX_SIZEOF : TCTX_ALIGNOF,
+                                type, !complain))
+    {
+      if (!complain)
+       return error_mark_node;
+      value = size_one_node;
+    }
   else
     {
       if (is_sizeof)
@@ -3720,7 +3730,10 @@ c_alignof_expr (location_t loc, tree exp
 {
   tree t;
 
-  if (VAR_OR_FUNCTION_DECL_P (expr))
+  if (!verify_type_context (loc, TCTX_ALIGNOF, TREE_TYPE (expr)))
+    t = size_one_node;
+
+  else if (VAR_OR_FUNCTION_DECL_P (expr))
     t = size_int (DECL_ALIGN_UNIT (expr));
 
   else if (TREE_CODE (expr) == COMPONENT_REF
Index: gcc/c/c-decl.c
===================================================================
--- gcc/c/c-decl.c      2019-11-08 08:31:41.845610282 +0000
+++ gcc/c/c-decl.c      2019-11-12 16:01:45.615584874 +0000
@@ -4938,7 +4938,7 @@ start_decl (struct c_declarator *declara
          {
            /* A complete type is ok if size is fixed.  */
 
-           if (TREE_CODE (TYPE_SIZE (TREE_TYPE (decl))) != INTEGER_CST
+           if (!poly_int_tree_p (TYPE_SIZE (TREE_TYPE (decl)))
                || C_DECL_VARIABLE_SIZE (decl))
              {
                error ("variable-sized object may not be initialized");
@@ -5221,6 +5221,15 @@ finish_decl (tree decl, location_t init_
 
       complete_flexible_array_elts (DECL_INITIAL (decl));
 
+      if (is_global_var (decl))
+       {
+         type_context_kind context = (DECL_THREAD_LOCAL_P (decl)
+                                      ? TCTX_THREAD_STORAGE
+                                      : TCTX_STATIC_STORAGE);
+         if (!verify_type_context (input_location, context, TREE_TYPE (decl)))
+           TREE_TYPE (decl) = error_mark_node;
+       }
+
       if (DECL_SIZE (decl) == NULL_TREE && TREE_TYPE (decl) != error_mark_node
          && COMPLETE_TYPE_P (TREE_TYPE (decl)))
        layout_decl (decl, 0);
@@ -5250,7 +5259,9 @@ finish_decl (tree decl, location_t init_
          && TREE_STATIC (decl))
        incomplete_record_decls.safe_push (decl);
 
-      if (is_global_var (decl) && DECL_SIZE (decl) != NULL_TREE)
+      if (is_global_var (decl)
+         && DECL_SIZE (decl) != NULL_TREE
+         && TREE_TYPE (decl) != error_mark_node)
        {
          if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST)
            constant_expression_warning (DECL_SIZE (decl));
@@ -5570,6 +5581,10 @@ build_compound_literal (location_t loc,
       return error_mark_node;
     }
 
+  if (TREE_STATIC (decl)
+      && !verify_type_context (loc, TCTX_STATIC_STORAGE, type))
+    return error_mark_node;
+
   stmt = build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl);
   complit = build1 (COMPOUND_LITERAL_EXPR, type, stmt);
   TREE_SIDE_EFFECTS (complit) = 1;
@@ -6271,6 +6286,12 @@ grokdeclarator (const struct c_declarato
            if (type == error_mark_node)
              continue;
 
+           if (!verify_type_context (loc, TCTX_ARRAY_ELEMENT, type))
+             {
+               type = error_mark_node;
+               continue;
+             }
+
            /* If size was specified, set ITYPE to a range-type for
               that size.  Otherwise, ITYPE remains null.  finish_decl
               may figure it out from an initial value.  */
@@ -7117,6 +7138,10 @@ grokdeclarator (const struct c_declarato
            if (orig_qual_indirect == 0)
              orig_qual_type = NULL_TREE;
          }
+       if (type != error_mark_node
+           && !verify_type_context (loc, TCTX_FIELD, type))
+         type = error_mark_node;
+
        type = c_build_qualified_type (type, type_quals, orig_qual_type,
                                       orig_qual_indirect);
        decl = build_decl (declarator->id_loc,
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c    2019-11-08 08:35:15.576104302 +0000
+++ gcc/c/c-typeck.c    2019-11-12 16:01:45.615584874 +0000
@@ -3892,6 +3892,7 @@ pointer_diff (location_t loc, tree op0,
   addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op0)));
   addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op1)));
   tree target_type = TREE_TYPE (TREE_TYPE (op0));
+  tree orig_op0 = op0;
   tree orig_op1 = op1;
 
   /* If the operands point into different address spaces, we need to
@@ -3962,6 +3963,10 @@ pointer_diff (location_t loc, tree op0,
   /* This generates an error if op1 is pointer to incomplete type.  */
   if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1))))
     error_at (loc, "arithmetic on pointer to an incomplete type");
+  else if (verify_type_context (loc, TCTX_POINTER_ARITH,
+                               TREE_TYPE (TREE_TYPE (orig_op0))))
+    verify_type_context (loc, TCTX_POINTER_ARITH,
+                        TREE_TYPE (TREE_TYPE (orig_op1)));
 
   op1 = c_size_in_bytes (target_type);
 
@@ -4614,6 +4619,9 @@ build_unary_op (location_t location, enu
                  pedwarn (location, OPT_Wpointer_arith,
                           "wrong type argument to decrement");
              }
+           else
+             verify_type_context (location, TCTX_POINTER_ARITH,
+                                  TREE_TYPE (argtype));
 
            inc = c_size_in_bytes (TREE_TYPE (argtype));
            inc = convert_to_ptrofftype_loc (location, inc);
Index: gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/sizeless-1.c
===================================================================
--- /dev/null   2019-09-17 11:41:18.176664108 +0100
+++ gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/sizeless-1.c    
2019-11-12 16:01:45.663584542 +0000
@@ -0,0 +1,217 @@
+/* { dg-options "-std=gnu99" } */
+
+#include <arm_sve.h>
+
+typedef signed char int8x32_t __attribute__((__vector_size__ (32)));
+
+/* Sizeless objects with global scope.  */
+
+svint8_t global_sve_sc; /* { dg-error {SVE type 'svint8_t' does not have a 
fixed size} } */
+static svint8_t local_sve_sc; /* { dg-error {SVE type 'svint8_t' does not have 
a fixed size} } */
+extern svint8_t extern_sve_sc; /* { dg-error {SVE type 'svint8_t' does not 
have a fixed size} } */
+__thread svint8_t tls_sve_sc; /* { dg-error {variables of type 'svint8_t' 
cannot have thread-local storage duration} } */
+_Atomic svint8_t atomic_sve_sc; /* { dg-error {SVE type 'svint8_t' does not 
have a fixed size} } */
+
+/* Sizeless arrays.  */
+
+typedef svint8_t array_type[2]; /* { dg-error {array elements cannot have SVE 
type 'svint8_t'} } */
+extern svint8_t extern_array[]; /* { dg-error {array elements cannot have SVE 
type 'svint8_t'} } */
+
+/* Sizeless fields.  */
+
+struct struct1 {
+  svint8_t a; /* { dg-error {fields cannot have SVE type 'svint8_t'} } */
+};
+
+union union1 {
+  svint8_t a; /* { dg-error {fields cannot have SVE type 'svint8_t'} } */
+};
+
+/* Pointers to sizeless types.  */
+
+svint8_t *global_sve_sc_ptr;
+svint8_t *invalid_sve_sc_ptr = &(svint8_t) { *global_sve_sc_ptr }; /* { 
dg-error {initializer element is not constant} } */
+  /* { dg-error {SVE type 'svint8_t' does not have a fixed size} "" { target 
*-*-* } .-1 } */
+
+/* Sizeless arguments and return values.  */
+
+void ext_consume_sve_sc (svint8_t);
+void ext_consume_varargs (int, ...);
+svint8_t ext_produce_sve_sc ();
+
+/* Main tests for statements and expressions.  */
+
+void
+statements (int n)
+{
+  /* Local declarations.  */
+
+  unsigned char va __attribute__((__vector_size__(2)));
+  svint8_t sve_sc1, sve_sc2;
+  _Atomic svint8_t atomic_sve_sc;
+  int8x32_t gnu_sc1;
+  svint16_t sve_sh1;
+  static svint8_t local_static_sve_sc; /* { dg-error {SVE type 'svint8_t' does 
not have a fixed size} } */
+
+  /* Layout queries.  */
+
+  sizeof (svint8_t); /* { dg-error {SVE type 'svint8_t' does not have a fixed 
size} } */
+  sizeof (sve_sc1); /* { dg-error {SVE type 'svint8_t' does not have a fixed 
size} } */
+  sizeof (ext_produce_sve_sc ()); /* { dg-error {SVE type 'svint8_t' does not 
have a fixed size} } */
+  _Alignof (svint8_t); /* { dg-error {SVE type 'svint8_t' does not have a 
defined alignment} } */
+  _Alignof (sve_sc1); /* { dg-error {SVE type 'svint8_t' does not have a 
defined alignment} } */
+  _Alignof (ext_produce_sve_sc ()); /* { dg-error {SVE type 'svint8_t' does 
not have a defined alignment} } */
+
+  /* Initialization.  */
+
+  svint8_t init_sve_sc1 = sve_sc1;
+  svint8_t init_sve_sc2 = sve_sh1; /* { dg-error {incompatible types when 
initializing type 'svint8_t' using type 'svint16_t'} } */
+  svint8_t init_sve_sc3 = {}; /* { dg-error {empty scalar initializer} } */
+
+  int initi_a = sve_sc1; /* { dg-error {incompatible types when initializing 
type 'int' using type 'svint8_t'} } */
+  int initi_b = { sve_sc1 }; /* { dg-error {incompatible types when 
initializing type 'int' using type 'svint8_t'} } */
+
+  /* Compound literals.  */
+
+  (svint8_t) {}; /* { dg-error {empty scalar initializer} } */
+  (svint8_t) { sve_sc1 };
+
+  (int) { sve_sc1 }; /* { dg-error {incompatible types when initializing type 
'int' using type 'svint8_t'} } */
+
+  /* Arrays.  */
+
+  svint8_t array[2]; /* { dg-error {array elements cannot have SVE type 
'svint8_t'} } */
+  svint8_t zero_length_array[0]; /* { dg-error {array elements cannot have SVE 
type 'svint8_t'} } */
+  svint8_t empty_init_array[] = {}; /* { dg-error {array elements cannot have 
SVE type 'svint8_t'} } */
+                                   /* { dg-error {empty scalar initializer} "" 
{ target *-*-* } .-1 } */
+  typedef svint8_t vla_type[n]; /* { dg-error {array elements cannot have SVE 
type 'svint8_t'} } */
+
+  /* Assignment.  */
+
+  n = sve_sc1; /* { dg-error {incompatible types when assigning to type 'int' 
from type 'svint8_t'} } */
+
+  sve_sc1 = 0; /* { dg-error {incompatible types when assigning to type 
'svint8_t' from type 'int'} } */
+  sve_sc1 = sve_sc2;
+  sve_sc1 = sve_sh1; /* { dg-error {incompatible types when assigning to type 
'svint8_t' from type 'svint16_t'} } */
+
+  /* Casting.  */
+
+  (void) sve_sc1;
+  (svint8_t) sve_sc1;
+
+  /* Addressing and dereferencing.  */
+
+  svint8_t *sve_sc_ptr = &sve_sc1;
+  int8x32_t *gnu_sc_ptr = &gnu_sc1;
+  sve_sc1 = *sve_sc_ptr;
+
+  /* Pointer assignment.  */
+
+  gnu_sc_ptr = sve_sc_ptr; /* { dg-warning {assignment to [^\n]* from 
incompatible pointer type} } */
+  sve_sc_ptr = gnu_sc_ptr; /* { dg-warning {assignment to [^\n]* from 
incompatible pointer type} } */
+
+  /* Pointer arithmetic.  */
+
+  ++sve_sc_ptr; /* { dg-error {arithmetic on pointer to SVE type 'svint8_t'} } 
*/
+  --sve_sc_ptr; /* { dg-error {arithmetic on pointer to SVE type 'svint8_t'} } 
*/
+  sve_sc_ptr++; /* { dg-error {arithmetic on pointer to SVE type 'svint8_t'} } 
*/
+  sve_sc_ptr--; /* { dg-error {arithmetic on pointer to SVE type 'svint8_t'} } 
*/
+  sve_sc_ptr += 0; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+  sve_sc_ptr += 1; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+  sve_sc_ptr -= 0; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+  sve_sc_ptr -= 1; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+  sve_sc_ptr - sve_sc_ptr; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+  gnu_sc_ptr - sve_sc_ptr; /* { dg-error {invalid operands to binary -} } */
+  sve_sc_ptr - gnu_sc_ptr; /* { dg-error {invalid operands to binary -} } */
+  sve_sc1 = sve_sc_ptr[0]; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+  sve_sc1 = sve_sc_ptr[1]; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+
+  /* Pointer comparison.  */
+
+  sve_sc_ptr == &sve_sc1;
+  sve_sc_ptr != &sve_sc1;
+  sve_sc_ptr < &sve_sc1;
+  sve_sc_ptr <= &sve_sc1;
+  sve_sc_ptr > &sve_sc1;
+  sve_sc_ptr >= &sve_sc1;
+  gnu_sc_ptr == sve_sc_ptr; /* { dg-warning {comparison of distinct pointer 
types lacks a cast} } */
+  gnu_sc_ptr != sve_sc_ptr; /* { dg-warning {comparison of distinct pointer 
types lacks a cast} } */
+  gnu_sc_ptr < sve_sc_ptr; /* { dg-warning {comparison of distinct pointer 
types lacks a cast} } */
+  gnu_sc_ptr <= sve_sc_ptr; /* { dg-warning {comparison of distinct pointer 
types lacks a cast} } */
+  gnu_sc_ptr > sve_sc_ptr; /* { dg-warning {comparison of distinct pointer 
types lacks a cast} } */
+  gnu_sc_ptr >= sve_sc_ptr; /* { dg-warning {comparison of distinct pointer 
types lacks a cast} } */
+  sve_sc_ptr == gnu_sc_ptr; /* { dg-warning {comparison of distinct pointer 
types lacks a cast} } */
+  sve_sc_ptr != gnu_sc_ptr; /* { dg-warning {comparison of distinct pointer 
types lacks a cast} } */
+  sve_sc_ptr < gnu_sc_ptr; /* { dg-warning {comparison of distinct pointer 
types lacks a cast} } */
+  sve_sc_ptr <= gnu_sc_ptr; /* { dg-warning {comparison of distinct pointer 
types lacks a cast} } */
+  sve_sc_ptr > gnu_sc_ptr; /* { dg-warning {comparison of distinct pointer 
types lacks a cast} } */
+  sve_sc_ptr >= gnu_sc_ptr; /* { dg-warning {comparison of distinct pointer 
types lacks a cast} } */
+
+  /* Conditional expressions.  */
+
+  0 ? sve_sc1 : sve_sc1;
+  0 ? sve_sc1 : sve_sh1; /* { dg-error {type mismatch in conditional 
expression} } */
+  0 ? sve_sc1 : 0; /* { dg-error {type mismatch in conditional expression} } */
+  0 ? 0 : sve_sc1; /* { dg-error {type mismatch in conditional expression} } */
+  0 ?: sve_sc1; /* { dg-error {type mismatch in conditional expression} } */
+  0 ? sve_sc_ptr : sve_sc_ptr;
+  0 ? sve_sc_ptr : gnu_sc_ptr; /* { dg-warning {pointer type mismatch in 
conditional expression} } */
+  0 ? gnu_sc_ptr : sve_sc_ptr; /* { dg-warning {pointer type mismatch in 
conditional expression} } */
+
+  /* Generic associations.  */
+
+  _Generic (sve_sc1, default: 100);
+  _Generic (1, svint8_t: 10, default: 20);
+
+  /* Function arguments.  */
+
+  ext_consume_sve_sc (sve_sc1);
+  ext_consume_sve_sc (sve_sh1); /* { dg-error {incompatible type for argument 
1 of 'ext_consume_sve_sc'} } */
+  ext_consume_varargs (sve_sc1); /* { dg-error {incompatible type for argument 
1 of 'ext_consume_varargs'} } */
+  ext_consume_varargs (1, sve_sc1);
+
+  /* Function returns.  */
+
+  ext_produce_sve_sc ();
+  sve_sc1 = ext_produce_sve_sc ();
+  sve_sh1 = ext_produce_sve_sc (); /* { dg-error {incompatible types when 
assigning to type 'svint16_t' from type 'svint8_t'} } */
+
+  /* Varargs processing.  */
+
+  __builtin_va_list valist;
+  __builtin_va_arg (valist, svint8_t);
+
+  /* Statement expressions.  */
+
+  ({ sve_sc1; });
+  ({ svint8_t another_sve_sc = *sve_sc_ptr; another_sve_sc; });
+}
+
+/* Function parameters in definitions.  */
+
+void
+old_style (input_sve_sc) /* { dg-error {SVE type 'svint8_t' cannot be passed 
to an unprototyped function} } */
+     svint8_t input_sve_sc;
+{
+  svint8_t sve_sc1 = input_sve_sc;
+}
+
+void
+new_style_param (svint8_t input_sve_sc)
+{
+  svint8_t sve_sc1 = input_sve_sc;
+}
+
+/* Function return values in definitions.  */
+
+svint8_t
+good_return_sve_sc (svint8_t param)
+{
+  return param;
+}
+
+svint8_t
+bad_return_sve_sc (svint16_t param)
+{
+  return param; /* { dg-error {incompatible types when returning type 
'svint16_t' but 'svint8_t' was expected} } */
+}
Index: gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/sizeless-2.c
===================================================================
--- /dev/null   2019-09-17 11:41:18.176664108 +0100
+++ gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/sizeless-2.c    
2019-11-12 16:01:45.663584542 +0000
@@ -0,0 +1,217 @@
+/* { dg-options "-std=gnu99 -msve-vector-bits=256" } */
+
+#include <arm_sve.h>
+
+typedef signed char int8x32_t __attribute__((__vector_size__ (32)));
+
+/* Sizeless objects with global scope.  */
+
+svint8_t global_sve_sc; /* { dg-error {SVE type 'svint8_t' does not have a 
fixed size} } */
+static svint8_t local_sve_sc; /* { dg-error {SVE type 'svint8_t' does not have 
a fixed size} } */
+extern svint8_t extern_sve_sc; /* { dg-error {SVE type 'svint8_t' does not 
have a fixed size} } */
+__thread svint8_t tls_sve_sc; /* { dg-error {variables of type 'svint8_t' 
cannot have thread-local storage duration} } */
+_Atomic svint8_t atomic_sve_sc; /* { dg-error {SVE type 'svint8_t' does not 
have a fixed size} } */
+
+/* Sizeless arrays.  */
+
+typedef svint8_t array_type[2]; /* { dg-error {array elements cannot have SVE 
type 'svint8_t'} } */
+extern svint8_t extern_array[]; /* { dg-error {array elements cannot have SVE 
type 'svint8_t'} } */
+
+/* Sizeless fields.  */
+
+struct struct1 {
+  svint8_t a; /* { dg-error {fields cannot have SVE type 'svint8_t'} } */
+};
+
+union union1 {
+  svint8_t a; /* { dg-error {fields cannot have SVE type 'svint8_t'} } */
+};
+
+/* Pointers to sizeless types.  */
+
+svint8_t *global_sve_sc_ptr;
+svint8_t *invalid_sve_sc_ptr = &(svint8_t) { *global_sve_sc_ptr }; /* { 
dg-error {initializer element is not constant} } */
+  /* { dg-error {SVE type 'svint8_t' does not have a fixed size} "" { target 
*-*-* } .-1 } */
+
+/* Sizeless arguments and return values.  */
+
+void ext_consume_sve_sc (svint8_t);
+void ext_consume_varargs (int, ...);
+svint8_t ext_produce_sve_sc ();
+
+/* Main tests for statements and expressions.  */
+
+void
+statements (int n)
+{
+  /* Local declarations.  */
+
+  unsigned char va __attribute__((__vector_size__(2)));
+  svint8_t sve_sc1, sve_sc2;
+  _Atomic svint8_t atomic_sve_sc;
+  int8x32_t gnu_sc1;
+  svint16_t sve_sh1;
+  static svint8_t local_static_sve_sc; /* { dg-error {SVE type 'svint8_t' does 
not have a fixed size} } */
+
+  /* Layout queries.  */
+
+  sizeof (svint8_t); /* { dg-error {SVE type 'svint8_t' does not have a fixed 
size} } */
+  sizeof (sve_sc1); /* { dg-error {SVE type 'svint8_t' does not have a fixed 
size} } */
+  sizeof (ext_produce_sve_sc ()); /* { dg-error {SVE type 'svint8_t' does not 
have a fixed size} } */
+  _Alignof (svint8_t); /* { dg-error {SVE type 'svint8_t' does not have a 
defined alignment} } */
+  _Alignof (sve_sc1); /* { dg-error {SVE type 'svint8_t' does not have a 
defined alignment} } */
+  _Alignof (ext_produce_sve_sc ()); /* { dg-error {SVE type 'svint8_t' does 
not have a defined alignment} } */
+
+  /* Initialization.  */
+
+  svint8_t init_sve_sc1 = sve_sc1;
+  svint8_t init_sve_sc2 = sve_sh1; /* { dg-error {incompatible types when 
initializing type 'svint8_t' using type 'svint16_t'} } */
+  svint8_t init_sve_sc3 = {}; /* { dg-error {empty scalar initializer} } */
+
+  int initi_a = sve_sc1; /* { dg-error {incompatible types when initializing 
type 'int' using type 'svint8_t'} } */
+  int initi_b = { sve_sc1 }; /* { dg-error {incompatible types when 
initializing type 'int' using type 'svint8_t'} } */
+
+  /* Compound literals.  */
+
+  (svint8_t) {}; /* { dg-error {empty scalar initializer} } */
+  (svint8_t) { sve_sc1 };
+
+  (int) { sve_sc1 }; /* { dg-error {incompatible types when initializing type 
'int' using type 'svint8_t'} } */
+
+  /* Arrays.  */
+
+  svint8_t array[2]; /* { dg-error {array elements cannot have SVE type 
'svint8_t'} } */
+  svint8_t zero_length_array[0]; /* { dg-error {array elements cannot have SVE 
type 'svint8_t'} } */
+  svint8_t empty_init_array[] = {}; /* { dg-error {array elements cannot have 
SVE type 'svint8_t'} } */
+                                   /* { dg-error {empty scalar initializer} "" 
{ target *-*-* } .-1 } */
+  typedef svint8_t vla_type[n]; /* { dg-error {array elements cannot have SVE 
type 'svint8_t'} } */
+
+  /* Assignment.  */
+
+  n = sve_sc1; /* { dg-error {incompatible types when assigning to type 'int' 
from type 'svint8_t'} } */
+
+  sve_sc1 = 0; /* { dg-error {incompatible types when assigning to type 
'svint8_t' from type 'int'} } */
+  sve_sc1 = sve_sc2;
+  sve_sc1 = sve_sh1; /* { dg-error {incompatible types when assigning to type 
'svint8_t' from type 'svint16_t'} } */
+
+  /* Casting.  */
+
+  (void) sve_sc1;
+  (svint8_t) sve_sc1;
+
+  /* Addressing and dereferencing.  */
+
+  svint8_t *sve_sc_ptr = &sve_sc1;
+  int8x32_t *gnu_sc_ptr = &gnu_sc1;
+  sve_sc1 = *sve_sc_ptr;
+
+  /* Pointer assignment.  */
+
+  gnu_sc_ptr = sve_sc_ptr;
+  sve_sc_ptr = gnu_sc_ptr;
+
+  /* Pointer arithmetic.  */
+
+  ++sve_sc_ptr; /* { dg-error {arithmetic on pointer to SVE type 'svint8_t'} } 
*/
+  --sve_sc_ptr; /* { dg-error {arithmetic on pointer to SVE type 'svint8_t'} } 
*/
+  sve_sc_ptr++; /* { dg-error {arithmetic on pointer to SVE type 'svint8_t'} } 
*/
+  sve_sc_ptr--; /* { dg-error {arithmetic on pointer to SVE type 'svint8_t'} } 
*/
+  sve_sc_ptr += 0; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+  sve_sc_ptr += 1; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+  sve_sc_ptr -= 0; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+  sve_sc_ptr -= 1; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+  sve_sc_ptr - sve_sc_ptr; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+  gnu_sc_ptr - sve_sc_ptr; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+  sve_sc_ptr - gnu_sc_ptr; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+  sve_sc1 = sve_sc_ptr[0]; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+  sve_sc1 = sve_sc_ptr[1]; /* { dg-error {arithmetic on pointer to SVE type 
'svint8_t'} } */
+
+  /* Pointer comparison.  */
+
+  sve_sc_ptr == &sve_sc1;
+  sve_sc_ptr != &sve_sc1;
+  sve_sc_ptr < &sve_sc1;
+  sve_sc_ptr <= &sve_sc1;
+  sve_sc_ptr > &sve_sc1;
+  sve_sc_ptr >= &sve_sc1;
+  gnu_sc_ptr == sve_sc_ptr;
+  gnu_sc_ptr != sve_sc_ptr;
+  gnu_sc_ptr < sve_sc_ptr;
+  gnu_sc_ptr <= sve_sc_ptr;
+  gnu_sc_ptr > sve_sc_ptr;
+  gnu_sc_ptr >= sve_sc_ptr;
+  sve_sc_ptr == gnu_sc_ptr;
+  sve_sc_ptr != gnu_sc_ptr;
+  sve_sc_ptr < gnu_sc_ptr;
+  sve_sc_ptr <= gnu_sc_ptr;
+  sve_sc_ptr > gnu_sc_ptr;
+  sve_sc_ptr >= gnu_sc_ptr;
+
+  /* Conditional expressions.  */
+
+  0 ? sve_sc1 : sve_sc1;
+  0 ? sve_sc1 : sve_sh1; /* { dg-error {type mismatch in conditional 
expression} } */
+  0 ? sve_sc1 : 0; /* { dg-error {type mismatch in conditional expression} } */
+  0 ? 0 : sve_sc1; /* { dg-error {type mismatch in conditional expression} } */
+  0 ?: sve_sc1; /* { dg-error {type mismatch in conditional expression} } */
+  0 ? sve_sc_ptr : sve_sc_ptr;
+  0 ? sve_sc_ptr : gnu_sc_ptr;
+  0 ? gnu_sc_ptr : sve_sc_ptr;
+
+  /* Generic associations.  */
+
+  _Generic (sve_sc1, default: 100);
+  _Generic (1, svint8_t: 10, default: 20);
+
+  /* Function arguments.  */
+
+  ext_consume_sve_sc (sve_sc1);
+  ext_consume_sve_sc (sve_sh1); /* { dg-error {incompatible type for argument 
1 of 'ext_consume_sve_sc'} } */
+  ext_consume_varargs (sve_sc1); /* { dg-error {incompatible type for argument 
1 of 'ext_consume_varargs'} } */
+  ext_consume_varargs (1, sve_sc1);
+
+  /* Function returns.  */
+
+  ext_produce_sve_sc ();
+  sve_sc1 = ext_produce_sve_sc ();
+  sve_sh1 = ext_produce_sve_sc (); /* { dg-error {incompatible types when 
assigning to type 'svint16_t' from type 'svint8_t'} } */
+
+  /* Varargs processing.  */
+
+  __builtin_va_list valist;
+  __builtin_va_arg (valist, svint8_t);
+
+  /* Statement expressions.  */
+
+  ({ sve_sc1; });
+  ({ svint8_t another_sve_sc = *sve_sc_ptr; another_sve_sc; });
+}
+
+/* Function parameters in definitions.  */
+
+void
+old_style (input_sve_sc) /* { dg-error {SVE type 'svint8_t' cannot be passed 
to an unprototyped function} } */
+     svint8_t input_sve_sc;
+{
+  svint8_t sve_sc1 = input_sve_sc;
+}
+
+void
+new_style_param (svint8_t input_sve_sc)
+{
+  svint8_t sve_sc1 = input_sve_sc;
+}
+
+/* Function return values in definitions.  */
+
+svint8_t
+good_return_sve_sc (svint8_t param)
+{
+  return param;
+}
+
+svint8_t
+bad_return_sve_sc (svint16_t param)
+{
+  return param; /* { dg-error {incompatible types when returning type 
'svint16_t' but 'svint8_t' was expected} } */
+}

Reply via email to