diff mbox series

[C] Add a target hook that allows targets to verify type usage

Message ID mptimnpf55d.fsf@arm.com
State New
Headers show
Series [C] Add a target hook that allows targets to verify type usage | expand

Commit Message

Richard Sandiford Nov. 12, 2019, 4:09 p.m. UTC
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.sandiford@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.

Comments

Richard Sandiford Nov. 29, 2019, 10:57 a.m. UTC | #1
Ping

Richard Sandiford <richard.sandiford@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.sandiford@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} } */
+}
Joseph Myers Nov. 29, 2019, 9:18 p.m. UTC | #2
On Fri, 29 Nov 2019, Richard Sandiford wrote:

> Ping
> 
> Richard Sandiford <richard.sandiford@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.

This patch is OK.
diff mbox series

Patch

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} } */
+}