aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/c-family/ChangeLog8
-rw-r--r--gcc/c-family/c-common.c15
-rw-r--r--gcc/c/ChangeLog14
-rw-r--r--gcc/c/c-decl.c29
-rw-r--r--gcc/c/c-typeck.c8
-rw-r--r--gcc/config/aarch64/aarch64-protos.h3
-rw-r--r--gcc/config/aarch64/aarch64-sve-builtins.cc49
-rw-r--r--gcc/config/aarch64/aarch64.c12
-rw-r--r--gcc/doc/tm.texi13
-rw-r--r--gcc/doc/tm.texi.in2
-rw-r--r--gcc/target.def16
-rw-r--r--gcc/target.h29
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/sizeless-1.c217
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/sizeless-2.c217
-rw-r--r--gcc/tree.c15
17 files changed, 664 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0bfc23996ce..72c8d2e03d4 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,18 @@
+2019-11-30 Richard Sandiford <richard.sandiford@arm.com>
+
+ * 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.
+
2019-11-30 Jan Hubicka <hubicka@ucw.cz>
* cgraph.c (cgraph_node::dump): Dump unit_id and merged_extern_inline.
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index a26b1f28ead..763e5a269f6 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,11 @@
+2019-11-30 Richard Sandiford <richard.sandiford@arm.com>
+
+ * 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.
+
2019-11-27 Jason Merrill <jason@redhat.com>
* c-cppbuiltin.c (c_cpp_builtins): Update __cpp_deduction_guides.
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 5b9af1a34b3..2f389d2895a 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -3146,6 +3146,9 @@ pointer_int_sum (location_t loc, enum tree_code resultcode,
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));
@@ -3691,6 +3694,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)
@@ -3723,7 +3733,10 @@ c_alignof_expr (location_t loc, tree expr)
{
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
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index b69e82d5645..8fee474346f 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,17 @@
+2019-11-30 Richard Sandiford <richard.sandiford@arm.com>
+
+ * 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.
+
2019-11-29 Joseph Myers <joseph@codesourcery.com>
* c-parser.c (struct c_parser): Add members raw_tokens and
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 292a4cc849b..fa7dea5afb5 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -5021,7 +5021,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
{
/* 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");
@@ -5304,6 +5304,15 @@ finish_decl (tree decl, location_t init_loc, tree 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);
@@ -5333,7 +5342,9 @@ finish_decl (tree decl, location_t init_loc, tree 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));
@@ -5653,6 +5664,10 @@ build_compound_literal (location_t loc, tree type, tree init, bool non_const,
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;
@@ -6370,6 +6385,12 @@ grokdeclarator (const struct c_declarator *declarator,
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. */
@@ -7217,6 +7238,10 @@ grokdeclarator (const struct c_declarator *declarator,
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,
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 5f74a3b28d9..f9ab1e38b42 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -3892,6 +3892,7 @@ pointer_diff (location_t loc, tree op0, tree op1, tree *instrument_expr)
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, tree op1, tree *instrument_expr)
/* 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, enum tree_code code, tree xarg,
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);
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 5b1fc7b7b28..c16b9362ea9 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -715,6 +715,9 @@ namespace aarch64_sve {
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]);
diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc b/gcc/config/aarch64/aarch64-sve-builtins.cc
index 27736b99f1b..5dd7ccb74ff 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins.cc
@@ -3296,6 +3296,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;
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 94e664af52f..d0cbe13273f 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -16200,6 +16200,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. */
@@ -21860,6 +21869,9 @@ aarch64_libgcc_floating_mode_supported_p
#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
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 7116450f532..5b8b68bd710 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11976,6 +11976,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.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 403468682bf..1b061d70127 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -8087,6 +8087,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.
diff --git a/gcc/target.def b/gcc/target.def
index cce71cd5b20..e0e856979a9 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -5287,6 +5287,22 @@ This is currently used only by the C and C++ front ends.",
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\
diff --git a/gcc/target.h b/gcc/target.h
index 2c5b59be851..973d743a371 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -226,6 +226,35 @@ enum omp_device_kind_arch_isa {
will choose the first mode that works. */
const unsigned int VECT_COMPARE_COSTS = 1U << 0;
+/* 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;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4595d664efa..34d5a75a200 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2019-11-30 Richard Sandiford <richard.sandiford@arm.com>
+
+ * gcc.target/aarch64/sve/acle/general-c/sizeless-1.c: New test.
+ * gcc.target/aarch64/sve/acle/general-c/sizeless-2.c: Likewise.
+
2019-11-30 Jan Hubicka <hubicka@ucw.cz>
* g++.dg/lto/inline-crossmodule-1.h: New testcase.
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/sizeless-1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/sizeless-1.c
new file mode 100644
index 00000000000..ec892a3fc83
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/sizeless-1.c
@@ -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} } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/sizeless-2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/sizeless-2.c
new file mode 100644
index 00000000000..71743930098
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general-c/sizeless-2.c
@@ -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} } */
+}
diff --git a/gcc/tree.c b/gcc/tree.c
index 789f0a00f41..1bb37679f54 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -15123,6 +15123,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 {