Message ID | mptsglybplx.fsf@arm.com |
---|---|
State | New |
Headers | show |
Series | Ping: [PATCH][C++] Pass type uses through the verify_type_context hook | expand |
On Thu, Dec 05, 2019 at 06:21:14PM +0000, Richard Sandiford wrote: > Ping. > > Richard Sandiford <richard.sandiford@arm.com> writes: > > This patch makes the C++ frontend work with the verify_type_context hook > > [https://gcc.gnu.org/ml/gcc-patches/2019-11/msg00942.html]. We need > > some new type contexts for features that don't exist in C, but otherwise > > the patch is very similar to the C one. > > > > TCTX_CAPTURE_BY_COPY could really be treated as an instance of > > TCTX_FIELD, but the error message is better if we split it out. > > > > Tested on aarch64-linux-gnu and x86_64-linux-gnu. OK to install? ... > Index: gcc/cp/decl.c > =================================================================== > --- gcc/cp/decl.c 2019-12-04 10:58:40.000000000 +0000 > +++ gcc/cp/decl.c 2019-12-04 10:59:10.215988487 +0000 > @@ -5470,6 +5470,13 @@ start_decl_1 (tree decl, bool initialize > cp_apply_type_quals_to_decl (cp_type_quals (type), decl); > } > > + if (is_global_var (decl)) > + { > + type_context_kind context = (DECL_THREAD_LOCAL_P (decl) > + ? TCTX_THREAD_STORAGE > + : TCTX_STATIC_STORAGE); > + verify_type_context (input_location, context, TREE_TYPE (decl)); > + } > if (initialized) > /* Is it valid for this decl to have an initializer at all? */ > { > @@ -6527,6 +6534,12 @@ check_array_initializer (tree decl, tree > error ("elements of array %q#T have incomplete type", type); > return true; > } > + > + location_t loc = (decl && DECL_P (decl) > + ? DECL_SOURCE_LOCATION (decl) : input_location); Not a review but I suspect you could use location_of here. -- Marek Polacek • Red Hat, Inc. • 300 A St, Boston, MA
On 12/5/19 1:21 PM, Richard Sandiford wrote: > + else if (!verify_type_context (input_location, TCTX_EXCEPTIONS, type)) > + return false; > + > + else if (TYPE_REF_P (type) > + && !verify_type_context (input_location, TCTX_EXCEPTIONS, > + TREE_TYPE (type))) You could use the non_reference function to combine these. Jason
Jason Merrill <jason@redhat.com> writes: > On 12/5/19 1:21 PM, Richard Sandiford wrote: >> + else if (!verify_type_context (input_location, TCTX_EXCEPTIONS, type)) >> + return false; >> + >> + else if (TYPE_REF_P (type) >> + && !verify_type_context (input_location, TCTX_EXCEPTIONS, >> + TREE_TYPE (type))) > > You could use the non_reference function to combine these. Thanks. This patch fixes that and follows Marek's suggestion of using location_of in check_array_initializer. (I wondered whether to check for decl == error_mark_node as well, but that can't currently happen.) Tested on aarch64-linux-gnu and x86_64-linux-gnu. OK to install? Richard 2019-12-06 Richard Sandiford <richard.sandiford@arm.com> gcc/ * target.h (TCTX_ALLOCATION, TCTX_DEALLOCATION, TCTX_EXCEPTIONS) (TCTX_CAPTURE_BY_COPY): New type_context_kinds. * config/aarch64/aarch64-sve-builtins.cc (verify_type_context): Handle them. gcc/cp/ * decl.c (start_decl_1): Use verify_type_context to check whether the target allows variables of a particular type to have static or thread-local storage duration. (check_array_initializer): Use verify_type_context to check whether the target allows a particular type to be used as an array element. (create_array_type_for_decl): Likewise. (cp_finish_decl): Use verify_type_context to check whether the target allows static member variables of a particular type. (grokdeclarator): Likewise. Also use verify_type_context to check whether the target allows non-static member variables of a particular type. * except.c: Include target.h. (is_admissible_throw_operand_or_catch_parameter): Use verify_type_context to check whether the target allows particular types to be thrown and caught. * typeck2.c (add_exception_specifier): Likewise. * init.c (build_new_1): Use verify_type_context to check whether the target allows particular types to be dynamically allocated. (build_vec_delete_1, build_delete): Use verify_type_context to check whether the target allows particular types to be deleted. * lambda.c (add_capture): Use verify_type_context to check whether the target allows particular types to be captured by copy. * pt.c: Include target.h. (instantiate_class_template_1): Use verify_type_context to check whether the target allows non-static member variables of a particular type. * typeck.c (cxx_alignof_expr): Use verify_type_context to check whether the target allows the alignment of a particular type to be measured. (pointer_diff, cp_build_unary_op): Use verify_type_context to check whether the target allows arithmetic involving pointers to particular types. gcc/testsuite/ * g++.dg/ext/sve-sizeless-1.C: New test. * g++.dg/ext/sve-sizeless-2.C: Likewise. Index: gcc/target.h =================================================================== --- gcc/target.h 2019-12-04 13:13:48.000000000 +0000 +++ gcc/target.h 2019-12-06 14:11:28.233552680 +0000 @@ -249,7 +249,19 @@ enum type_context_kind { /* 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 + TCTX_POINTER_ARITH, + + /* Dynamically allocating objects of type T. */ + TCTX_ALLOCATION, + + /* Dynamically deallocating objects of type T. */ + TCTX_DEALLOCATION, + + /* Throwing or catching an object of type T. */ + TCTX_EXCEPTIONS, + + /* Capturing objects of type T by value in a closure. */ + TCTX_CAPTURE_BY_COPY }; extern bool verify_type_context (location_t, type_context_kind, const_tree, Index: gcc/config/aarch64/aarch64-sve-builtins.cc =================================================================== --- gcc/config/aarch64/aarch64-sve-builtins.cc 2019-12-04 13:13:48.000000000 +0000 +++ gcc/config/aarch64/aarch64-sve-builtins.cc 2019-12-06 14:11:28.217552787 +0000 @@ -3352,6 +3352,26 @@ verify_type_context (location_t loc, typ if (!silent_p) error_at (loc, "array elements cannot have SVE type %qT", type); return false; + + case TCTX_ALLOCATION: + if (!silent_p) + error_at (loc, "cannot allocate objects with SVE type %qT", type); + return false; + + case TCTX_DEALLOCATION: + if (!silent_p) + error_at (loc, "cannot delete objects with SVE type %qT", type); + return false; + + case TCTX_EXCEPTIONS: + if (!silent_p) + error_at (loc, "cannot throw or catch SVE type %qT", type); + return false; + + case TCTX_CAPTURE_BY_COPY: + if (!silent_p) + error_at (loc, "capture by copy of SVE type %qT", type); + return false; } gcc_unreachable (); } Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c 2019-12-06 10:31:11.638430940 +0000 +++ gcc/cp/decl.c 2019-12-06 14:11:28.221552762 +0000 @@ -5470,6 +5470,13 @@ start_decl_1 (tree decl, bool initialize cp_apply_type_quals_to_decl (cp_type_quals (type), decl); } + if (is_global_var (decl)) + { + type_context_kind context = (DECL_THREAD_LOCAL_P (decl) + ? TCTX_THREAD_STORAGE + : TCTX_STATIC_STORAGE); + verify_type_context (input_location, context, TREE_TYPE (decl)); + } if (initialized) /* Is it valid for this decl to have an initializer at all? */ { @@ -6535,6 +6542,11 @@ check_array_initializer (tree decl, tree error ("elements of array %q#T have incomplete type", type); return true; } + + location_t loc = (decl ? location_of (decl) : input_location); + if (!verify_type_context (loc, TCTX_ARRAY_ELEMENT, element_type)) + return true; + /* A compound literal can't have variable size. */ if (init && !decl && ((COMPLETE_TYPE_P (type) && !TREE_CONSTANT (TYPE_SIZE (type))) @@ -7482,6 +7494,8 @@ cp_finish_decl (tree decl, tree init, bo if (VAR_P (decl) && DECL_CLASS_SCOPE_P (decl) + && verify_type_context (DECL_SOURCE_LOCATION (decl), + TCTX_STATIC_STORAGE, type) && DECL_INITIALIZED_IN_CLASS_P (decl)) check_static_variable_definition (decl, type); @@ -10550,6 +10564,10 @@ create_array_type_for_decl (tree name, t break; } + if (!verify_type_context (name ? loc : input_location, + TCTX_ARRAY_ELEMENT, type)) + return error_mark_node; + /* [dcl.array] The constant expressions that specify the bounds of the arrays @@ -13254,6 +13272,14 @@ grokdeclarator (const cp_declarator *dec decl = NULL_TREE; } } + else if (!verify_type_context (input_location, + staticp + ? TCTX_STATIC_STORAGE + : TCTX_FIELD, type)) + { + type = error_mark_node; + decl = NULL_TREE; + } else { if (friendp) Index: gcc/cp/except.c =================================================================== --- gcc/cp/except.c 2019-12-04 13:13:48.000000000 +0000 +++ gcc/cp/except.c 2019-12-06 14:11:28.221552762 +0000 @@ -29,6 +29,7 @@ the Free Software Foundation; either ver #include "trans-mem.h" #include "attribs.h" #include "tree-iterator.h" +#include "target.h" static void push_eh_cleanup (tree); static tree prepare_eh_type (tree); @@ -927,6 +928,10 @@ is_admissible_throw_operand_or_catch_par if (!complete_ptr_ref_or_void_ptr_p (type, expr)) return false; + tree nonref_type = non_reference (type); + if (!verify_type_context (input_location, TCTX_EXCEPTIONS, nonref_type)) + return false; + /* 10.4/3 An abstract class shall not be used as a parameter type, as a function return type or as type of an explicit conversion. */ Index: gcc/cp/typeck2.c =================================================================== --- gcc/cp/typeck2.c 2019-12-05 14:20:16.965063368 +0000 +++ gcc/cp/typeck2.c 2019-12-06 14:11:28.233552680 +0000 @@ -33,6 +33,7 @@ the Free Software Foundation; either ver #include "varasm.h" #include "intl.h" #include "gcc-rich-location.h" +#include "target.h" static tree process_init_constructor (tree type, tree init, int nested, int flags, @@ -2401,6 +2402,9 @@ add_exception_specifier (tree list, tree ok = true; else if (processing_template_decl) ok = true; + else if (!verify_type_context (input_location, TCTX_EXCEPTIONS, core, + !(complain & tf_error))) + return error_mark_node; else { ok = true; Index: gcc/cp/init.c =================================================================== --- gcc/cp/init.c 2019-12-04 13:13:48.000000000 +0000 +++ gcc/cp/init.c 2019-12-06 14:11:28.221552762 +0000 @@ -3058,6 +3058,10 @@ build_new_1 (vec<tree, va_gc> **placemen complain); } + if (!verify_type_context (input_location, TCTX_ALLOCATION, elt_type, + !(complain & tf_error))) + return error_mark_node; + if (variably_modified_type_p (elt_type, NULL_TREE) && (complain & tf_error)) { error ("variably modified type not allowed in new-expression"); @@ -3942,6 +3946,10 @@ build_vec_delete_1 (tree base, tree maxi if (base == error_mark_node || maxindex == error_mark_node) return error_mark_node; + if (!verify_type_context (input_location, TCTX_DEALLOCATION, type, + !(complain & tf_error))) + return error_mark_node; + if (!COMPLETE_TYPE_P (type)) { if (complain & tf_warning) @@ -4827,6 +4835,11 @@ build_delete (tree otype, tree addr, spe if (!VOID_TYPE_P (type)) { complete_type (type); + if (deleting + && !verify_type_context (input_location, TCTX_DEALLOCATION, type, + !(complain & tf_error))) + return error_mark_node; + if (!COMPLETE_TYPE_P (type)) { if (complain & tf_warning) Index: gcc/cp/lambda.c =================================================================== --- gcc/cp/lambda.c 2019-12-04 13:13:48.000000000 +0000 +++ gcc/cp/lambda.c 2019-12-06 14:11:28.225552732 +0000 @@ -30,6 +30,7 @@ #include "tree-iterator.h" #include "toplev.h" #include "gimplify.h" +#include "target.h" /* Constructor for a lambda expression. */ @@ -579,6 +580,9 @@ add_capture (tree lambda, tree id, tree cxx_incomplete_type_inform (type); return error_mark_node; } + else if (!verify_type_context (input_location, + TCTX_CAPTURE_BY_COPY, type)) + return error_mark_node; } } Index: gcc/cp/pt.c =================================================================== --- gcc/cp/pt.c 2019-12-05 14:20:16.969063342 +0000 +++ gcc/cp/pt.c 2019-12-06 14:11:28.229552706 +0000 @@ -42,6 +42,7 @@ the Free Software Foundation; either ver #include "gimplify.h" #include "gcc-rich-location.h" #include "selftest.h" +#include "target.h" /* The type of functions taking a tree, and some additional data, and returning an int. */ @@ -11815,6 +11816,9 @@ instantiate_class_template_1 (tree type) error ("flexible array member %qD in union", r); TREE_TYPE (r) = error_mark_node; } + else if (!verify_type_context (input_location, + TCTX_FIELD, rtype)) + TREE_TYPE (r) = error_mark_node; } /* If it is a TYPE_DECL for a class-scoped ENUMERAL_TYPE, Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c 2019-12-04 13:13:48.000000000 +0000 +++ gcc/cp/typeck.c 2019-12-06 14:11:28.229552706 +0000 @@ -1824,7 +1824,14 @@ cxx_alignof_expr (tree e, tsubst_flags_t e = mark_type_use (e); - if (VAR_P (e)) + if (!verify_type_context (input_location, TCTX_ALIGNOF, TREE_TYPE (e), + !(complain & tf_error))) + { + if (!(complain & tf_error)) + return error_mark_node; + t = size_one_node; + } + else if (VAR_P (e)) t = size_int (DECL_ALIGN_UNIT (e)); else if (bitfield_p (e)) { @@ -5778,6 +5785,13 @@ pointer_diff (location_t loc, tree op0, else return error_mark_node; } + else if (!verify_type_context (loc, TCTX_POINTER_ARITH, + TREE_TYPE (TREE_TYPE (op0)), + !(complain & tf_error)) + || !verify_type_context (loc, TCTX_POINTER_ARITH, + TREE_TYPE (TREE_TYPE (op1)), + !(complain & tf_error))) + return error_mark_node; /* Determine integer type result of the subtraction. This will usually be the same as the result type (ptrdiff_t), but may need to be a wider @@ -6572,6 +6586,10 @@ cp_build_unary_op (enum tree_code code, else return error_mark_node; } + else if (!verify_type_context (location, TCTX_POINTER_ARITH, + TREE_TYPE (argtype), + !(complain & tf_error))) + return error_mark_node; inc = cxx_sizeof_nowarn (TREE_TYPE (argtype)); } Index: gcc/testsuite/g++.dg/ext/sve-sizeless-1.C =================================================================== --- /dev/null 2019-09-17 11:41:18.176664108 +0100 +++ gcc/testsuite/g++.dg/ext/sve-sizeless-1.C 2019-12-06 14:11:28.233552680 +0000 @@ -0,0 +1,420 @@ +// { dg-do compile { target aarch64*-*-* } } +// { dg-options "-Wclass-memaccess" } + +#pragma GCC target "+sve" + +typedef __SIZE_TYPE__ size_t; +inline void *operator new (size_t, void *__p) throw() { return __p; } + +#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} } + +// 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 member variables. + +struct struct1 { + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } +}; + +union union1 { + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } +}; + +#if __cplusplus >= 201103L +struct static_sve_sc { + static svint8_t sve_sc1 = {}; // { dg-error {SVE type 'svint8_t' does not have a fixed size} "" { target c++11 } } +}; +#endif + +// Sizeless member variables in templated structures. + +template<typename T> +struct templated_struct1 { + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } +}; + +template<typename T> +struct templated_struct2 { + T a; // { dg-error {member variables cannot have SVE type '(svint8_t|__SVInt8_t)'} } +}; + +template class templated_struct2<svint8_t>; + +template<typename T> +struct templated_struct3 { + T &a; +}; + +template class templated_struct3<svint8_t>; + +#if __cplusplus >= 201103L +template<typename T> +struct templated_struct4 { + static T a; // { dg-error {SVE type '(svint8_t|__SVInt8_t)' does not have a fixed size} "" { target c++11 } } + static T b = {}; // { dg-error {SVE type '(svint8_t|__SVInt8_t)' does not have a fixed size} "" { target c++11 } } +}; + +template class templated_struct4<svint8_t>; +#endif + +template<typename T> struct templated_struct5 : T {}; // { dg-error {base type '[^']*' fails to be a struct or class type} } +template class templated_struct5<svint8_t>; + +#if __cplusplus >= 201103L +template<int N> using typedef_sizeless1 = svint8_t; +template<int N> using typedef_sizeless1 = svint8_t; // { dg-error {redefinition of 'template<int N> using typedef_sizeless1 = svint8_t'} "" { target c++11 } } +template<typename T> using array = T[2]; +#endif + +// Pointers to sizeless types. + +svint8_t *global_sve_sc_ptr; + +// Sizeless arguments and return values. + +void ext_consume_sve_sc (svint8_t); +void ext_consume_const_int_ref (const int &); +void ext_consume_varargs (int, ...); +svint8_t ext_produce_sve_sc (); + +// Sizeless types in throw specifications. + +#if __cplusplus < 201103L +void thrower1 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +void thrower2 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +void thrower3 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +#endif + +// Main tests for statements and expressions. + +void +statements (int n) +{ + // Local declarations. + + svint8_t sve_sc1, sve_sc2; + volatile svint8_t volatile_sve_sc1; + int8x32_t gnu_sc1; + svint16_t sve_sh1; + + // 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} } + +#if __cplusplus >= 201103L + array<svint8_t> foo = {}; // { dg-error {array elements cannot have SVE type '(svint8_t|__SVInt8_t)'} "" { target c++11 } } +#endif + + // Initialization. + + int init_int1 = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } + int init_int2 = { sve_sc1 }; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } + + svint8_t init_sve_sc1 (sve_sc1); + svint8_t init_sve_sc2 (sve_sh1); // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + svint8_t init_sve_sc3 = sve_sc1; + svint8_t init_sve_sc4 = sve_sh1; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + svint8_t init_sve_sc5 = {}; + svint8_t init_sve_sc6 = { sve_sc1 }; + svint8_t init_sve_sc7 = { sve_sh1 }; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + + // Constructor calls. + + (0, svint8_t ()); + + // Lvalue reference binding + + svint8_t &lvalue_ref_sve_sc1 = sve_sc1; + svint8_t &lvalue_ref_sve_sc2 = ext_produce_sve_sc (); // { dg-error {cannot bind non-const lvalue reference of type 'svint8_t&' to an rvalue of type 'svint8_t'} } + svint8_t &lvalue_ref_sve_sc3 = sve_sh1; // { dg-error {invalid initialization of reference of type 'svint8_t&' from expression of type 'svint16_t'} } + + const svint8_t &const_lvalue_ref_sve_sc1 = sve_sc1; + const svint8_t &const_lvalue_ref_sve_sc2 = ext_produce_sve_sc (); + const svint8_t &const_lvalue_ref_sve_sc3 = sve_sh1; // { dg-error {invalid initialization of reference of type 'const svint8_t&' from expression of type 'svint16_t'} } + + // Compound literals. + + (int) { sve_sc1 }; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } + + // 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'} } + + // Assignment. + + n = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int' in assignment} } + + sve_sc1 = 0; // { dg-error {cannot convert 'int' to 'svint8_t' in assignment} } + sve_sc1 = sve_sc1; + sve_sc1 = gnu_sc1; // { dg-error {cannot convert 'int8x32_t'[^\n]* to 'svint8_t' in assignment} } + gnu_sc1 = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int8x32_t'} } + sve_sc1 = sve_sh1; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + + // Casting. + + (void) sve_sc1; + (void) volatile_sve_sc1; + (void) *&volatile_sve_sc1; + + // Addressing and dereferencing. + + svint8_t *sve_sc_ptr = &sve_sc1; + int8x32_t *gnu_sc_ptr = &gnu_sc1; + sve_sc_ptr = (svint16_t *) 0; // { dg-error {cannot convert 'svint16_t\*' to 'svint8_t\*' in assignment} } + + // Pointer assignment. + + gnu_sc_ptr = sve_sc_ptr; // { dg-error {cannot convert 'svint8_t\*' to 'int8x32_t\*'} } + sve_sc_ptr = gnu_sc_ptr; // { dg-error {cannot convert 'int8x32_t\*'[^\n]* to 'svint8_t\*'} } + + // 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 of types 'int8x32_t\*'[^\n]* and 'svint8_t\*' to binary 'operator-'} } + sve_sc_ptr - gnu_sc_ptr; // { dg-error {invalid operands of types 'svint8_t\*' and 'int8x32_t\*'[^\n]* to binary 'operator-'} } + 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-error {comparison between distinct pointer types [^\n]*lacks a cast} } + gnu_sc_ptr != sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + gnu_sc_ptr < sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + gnu_sc_ptr <= sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + gnu_sc_ptr > sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + gnu_sc_ptr >= sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + sve_sc_ptr == gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + sve_sc_ptr != gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + sve_sc_ptr < gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + sve_sc_ptr <= gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + sve_sc_ptr > gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + sve_sc_ptr >= gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + + // New and delete. + + new svint8_t; // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + new svint8_t (); // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + + new (global_sve_sc_ptr) svint8_t; // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + new (global_sve_sc_ptr) svint8_t (); // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + + sve_sc1.~svint8_t(); // { dg-error {expected class-name before '\(' token} } + delete sve_sc_ptr; // { dg-error {cannot delete objects with SVE type '(svint8_t|__SVInt8_t)'} } + delete[] sve_sc_ptr; // { dg-error {cannot delete objects with SVE type 'svint8_t'} } + + // Conditional expressions. + + 0 ? sve_sc1 : sve_sc1; + 0 ? sve_sc1 : sve_sh1; // { dg-error {different types 'svint8_t' and 'svint16_t'} } + 0 ? sve_sc1 : 0; // { dg-error {different types 'svint8_t' and 'int'} } + 0 ? 0 : sve_sc1; // { dg-error {different types 'int' and 'svint8_t'} } + 0 ? sve_sc1 : sve_sc1; + 0 ? sve_sc_ptr : sve_sc_ptr; + 0 ? sve_sc_ptr : gnu_sc_ptr; // { dg-error {conditional expression between distinct pointer types [^\n]*lacks a cast} } + 0 ? gnu_sc_ptr : sve_sc_ptr; // { dg-error {conditional expression between distinct pointer types [^\n]*lacks a cast} } + + // Function arguments. + + ext_consume_sve_sc (sve_sc1); + ext_consume_sve_sc (sve_sh1); // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + ext_consume_const_int_ref (sve_sc1); // { dg-error {invalid initialization of reference of type 'const int&' from expression of type 'svint8_t'} } + ext_consume_varargs (sve_sc1); // { dg-error {cannot convert 'svint8_t' to 'int'} } + 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 {cannot convert 'svint8_t' to 'svint16_t' in assignment} } + + // Auto + +#if __cplusplus >= 201103L + auto auto_sve_sc1 = sve_sc1; + auto auto_sve_sc1_return = ext_produce_sve_sc (); +#endif + + // Varargs processing. + + __builtin_va_list valist; + __builtin_va_arg (valist, svint8_t); + + // Other built-ins + + __builtin_launder (sve_sc1); // { dg-error {non-pointer argument to '__builtin_launder'} } + __builtin_memcpy (&sve_sc1, &sve_sc2, 2); + + // Lambdas + +#if __cplusplus >= 201103L + [sve_sc1] () {}; // { dg-error {capture by copy of SVE type 'svint8_t'} "" { target c++11 } } + [=] () { &sve_sc1; }; // { dg-error {capture by copy of SVE type 'svint8_t'} "" { target c++11 } } + [&sve_sc1] () { sve_sc1 = sve_sc2; }; // { dg-error {'sve_sc2' is not captured} "" { target c++11 } } + [&sve_sc1, &sve_sc2] () { sve_sc1 = sve_sc2; }; + [&] () { sve_sc1 = sve_sc2; }; + [] () { return ext_produce_sve_sc (); } (); +#endif + + // Exceptions + + throw svint8_t (); // { dg-error {cannot throw or catch SVE type 'svint8_t'} } + try {} catch (svint8_t x) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} } + try {} catch (svint8_t &x) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} } + try {} catch (svint8_t *x) {} +#if __cplusplus < 201103L + thrower2 (); +#endif + + // Use in traits. Doesn't use static_assert so that tests work with + // earlier -std=s. + + { typedef int f[__has_nothrow_assign (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_assign (svint8_t) ? 1 : -1]; } + { typedef int f[__has_nothrow_constructor (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_constructor (svint8_t) ? 1 : -1]; } + { typedef int f[__has_nothrow_copy (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_copy (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_destructor (svint8_t) ? 1 : -1]; } + { typedef int f[__has_unique_object_representations (svint8_t) ? 1 : -1]; } + { typedef int f[!__has_virtual_destructor (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_abstract (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_aggregate (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_base_of (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_base_of (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[!__is_class (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_empty (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_enum (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_final (svint8_t) ? 1 : -1]; } + { typedef int f[__is_pod (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_polymorphic (svint8_t) ? 1 : -1]; } + { typedef int f[__is_same_as (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_same_as (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_same_as (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[__is_same_as (svint8_t *, svint8_t *) ? 1 : -1]; } + { typedef int f[!__is_same_as (svint8_t *, int8x32_t *) ? 1 : -1]; } + { typedef int f[!__is_same_as (int8x32_t *, svint8_t *) ? 1 : -1]; } + { typedef int f[!__is_same_as (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_same_as (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[__is_trivial (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_union (svint8_t) ? 1 : -1]; } + { typedef int f[__is_trivially_copyable (svint8_t) ? 1 : -1]; } + /* The intention is that svint8_t should behave like int8x32_t here. If the behavior + for int8x32_t changes then the behavior for svint8_t should change in the same + way. */ + { typedef int f[!__is_trivially_assignable (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (svint8_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_constructible (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_constructible (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_constructible (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_trivially_constructible (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[__is_constructible (svint8_t) ? 1 : -1]; } + { typedef int f[__is_constructible (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[__is_constructible (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_constructible (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_constructible (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_constructible (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_constructible (svint8_t, svint16_t) ? 1 : -1]; } +} + +// Function parameters in definitions. + +void +unnamed_st1 (svint8_t) +{ +} + +void +named_st1 (svint8_t param1) +{ + svint8_t sve_sc1 = param1; +} + +// Function return values in definitions. + +svint8_t +ret_st1 (svint8_t param) +{ + return param; +} + +svint8_t +bad_ret_st1 (svint16_t param) +{ + return param; // { dg-error {cannot convert 'svint16_t' to 'svint8_t' in return} } +} + +#if __cplusplus >= 201103L +template<typename T> +void +const_to_sve_sc (T i) +{ + constexpr svint8_t a = (svint8_t) i; +} +#endif + +template<typename T> +int +get_x (T *a) +{ + return a->a; // { dg-error {request for member 'a' in '\* a', which is of non-class type} } +} +template int get_x<svint8_t>(svint8_t *); + +#if __cplusplus < 201103L +void thrower3 () throw (svint8_t) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +#endif + +// Using "auto" as a return type. + +#if __cplusplus >= 201402L +auto auto_ret_sve_sc (svint8_t *ptr) { return *ptr; } +const auto &auto_ret_const_sve_sc_ref (svint8_t *ptr) { return *ptr; } +auto &auto_ret_sve_sc_ref (svint8_t *ptr) { return *ptr; } +auto &&auto_ret_sve_sc_rvalue_ref (svint8_t *ptr) { return *ptr; } +#endif Index: gcc/testsuite/g++.dg/ext/sve-sizeless-2.C =================================================================== --- /dev/null 2019-09-17 11:41:18.176664108 +0100 +++ gcc/testsuite/g++.dg/ext/sve-sizeless-2.C 2019-12-06 14:11:28.233552680 +0000 @@ -0,0 +1,420 @@ +// { dg-do compile { target aarch64*-*-* } } +// { dg-options "-Wclass-memaccess -msve-vector-bits=256" } + +#pragma GCC target "+sve" + +typedef __SIZE_TYPE__ size_t; +inline void *operator new (size_t, void *__p) throw() { return __p; } + +#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} } + +// 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 member variables. + +struct struct1 { + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } +}; + +union union1 { + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } +}; + +#if __cplusplus >= 201103L +struct static_sve_sc { + static svint8_t sve_sc1 = {}; // { dg-error {SVE type 'svint8_t' does not have a fixed size} "" { target c++11 } } +}; +#endif + +// Sizeless member variables in templated structures. + +template<typename T> +struct templated_struct1 { + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } +}; + +template<typename T> +struct templated_struct2 { + T a; // { dg-error {member variables cannot have SVE type '(svint8_t|__SVInt8_t)'} } +}; + +template class templated_struct2<svint8_t>; + +template<typename T> +struct templated_struct3 { + T &a; +}; + +template class templated_struct3<svint8_t>; + +#if __cplusplus >= 201103L +template<typename T> +struct templated_struct4 { + static T a; // { dg-error {SVE type '(svint8_t|__SVInt8_t)' does not have a fixed size} "" { target c++11 } } + static T b = {}; // { dg-error {SVE type '(svint8_t|__SVInt8_t)' does not have a fixed size} "" { target c++11 } } +}; + +template class templated_struct4<svint8_t>; +#endif + +template<typename T> struct templated_struct5 : T {}; // { dg-error {base type '[^']*' fails to be a struct or class type} } +template class templated_struct5<svint8_t>; + +#if __cplusplus >= 201103L +template<int N> using typedef_sizeless1 = svint8_t; +template<int N> using typedef_sizeless1 = svint8_t; // { dg-error {redefinition of 'template<int N> using typedef_sizeless1 = svint8_t'} "" { target c++11 } } +template<typename T> using array = T[2]; +#endif + +// Pointers to sizeless types. + +svint8_t *global_sve_sc_ptr; + +// Sizeless arguments and return values. + +void ext_consume_sve_sc (svint8_t); +void ext_consume_const_int_ref (const int &); +void ext_consume_varargs (int, ...); +svint8_t ext_produce_sve_sc (); + +// Sizeless types in throw specifications. + +#if __cplusplus < 201103L +void thrower1 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +void thrower2 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +void thrower3 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +#endif + +// Main tests for statements and expressions. + +void +statements (int n) +{ + // Local declarations. + + svint8_t sve_sc1, sve_sc2; + volatile svint8_t volatile_sve_sc1; + int8x32_t gnu_sc1; + svint16_t sve_sh1; + + // 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} } + +#if __cplusplus >= 201103L + array<svint8_t> foo = {}; // { dg-error {array elements cannot have SVE type '(svint8_t|__SVInt8_t)'} "" { target c++11 } } +#endif + + // Initialization. + + int init_int1 = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } + int init_int2 = { sve_sc1 }; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } + + svint8_t init_sve_sc1 (sve_sc1); + svint8_t init_sve_sc2 (sve_sh1); // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + svint8_t init_sve_sc3 = sve_sc1; + svint8_t init_sve_sc4 = sve_sh1; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + svint8_t init_sve_sc5 = {}; + svint8_t init_sve_sc6 = { sve_sc1 }; + svint8_t init_sve_sc7 = { sve_sh1 }; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + + // Constructor calls. + + (0, svint8_t ()); + + // Lvalue reference binding + + svint8_t &lvalue_ref_sve_sc1 = sve_sc1; + svint8_t &lvalue_ref_sve_sc2 = ext_produce_sve_sc (); // { dg-error {cannot bind non-const lvalue reference of type 'svint8_t&' to an rvalue of type 'svint8_t'} } + svint8_t &lvalue_ref_sve_sc3 = sve_sh1; // { dg-error {invalid initialization of reference of type 'svint8_t&' from expression of type 'svint16_t'} } + + const svint8_t &const_lvalue_ref_sve_sc1 = sve_sc1; + const svint8_t &const_lvalue_ref_sve_sc2 = ext_produce_sve_sc (); + const svint8_t &const_lvalue_ref_sve_sc3 = sve_sh1; // { dg-error {invalid initialization of reference of type 'const svint8_t&' from expression of type 'svint16_t'} } + + // Compound literals. + + (int) { sve_sc1 }; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } + + // 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'} } + + // Assignment. + + n = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int' in assignment} } + + sve_sc1 = 0; // { dg-error {cannot convert 'int' to 'svint8_t' in assignment} } + sve_sc1 = sve_sc1; + sve_sc1 = gnu_sc1; + gnu_sc1 = sve_sc1; + sve_sc1 = sve_sh1; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + + // Casting. + + (void) sve_sc1; + (void) volatile_sve_sc1; + (void) *&volatile_sve_sc1; + + // Addressing and dereferencing. + + svint8_t *sve_sc_ptr = &sve_sc1; + int8x32_t *gnu_sc_ptr = &gnu_sc1; + sve_sc_ptr = (svint16_t *) 0; // { dg-error {cannot convert 'svint16_t\*' to 'svint8_t\*' in assignment} } + + // 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; + + // New and delete. + + new svint8_t; // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + new svint8_t (); // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + + new (global_sve_sc_ptr) svint8_t; // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + new (global_sve_sc_ptr) svint8_t (); // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + + sve_sc1.~svint8_t(); // { dg-error {expected class-name before '\(' token} } + delete sve_sc_ptr; // { dg-error {cannot delete objects with SVE type '(svint8_t|__SVInt8_t)'} } + delete[] sve_sc_ptr; // { dg-error {cannot delete objects with SVE type 'svint8_t'} } + + // Conditional expressions. + + 0 ? sve_sc1 : sve_sc1; + 0 ? sve_sc1 : sve_sh1; // { dg-error {different types 'svint8_t' and 'svint16_t'} } + 0 ? sve_sc1 : 0; // { dg-error {different types 'svint8_t' and 'int'} } + 0 ? 0 : sve_sc1; // { dg-error {different types 'int' and 'svint8_t'} } + 0 ? sve_sc1 : sve_sc1; + 0 ? sve_sc_ptr : sve_sc_ptr; + 0 ? sve_sc_ptr : gnu_sc_ptr; + 0 ? gnu_sc_ptr : sve_sc_ptr; + + // Function arguments. + + ext_consume_sve_sc (sve_sc1); + ext_consume_sve_sc (sve_sh1); // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + ext_consume_const_int_ref (sve_sc1); // { dg-error {invalid initialization of reference of type 'const int&' from expression of type 'svint8_t'} } + ext_consume_varargs (sve_sc1); // { dg-error {cannot convert 'svint8_t' to 'int'} } + 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 {cannot convert 'svint8_t' to 'svint16_t' in assignment} } + + // Auto + +#if __cplusplus >= 201103L + auto auto_sve_sc1 = sve_sc1; + auto auto_sve_sc1_return = ext_produce_sve_sc (); +#endif + + // Varargs processing. + + __builtin_va_list valist; + __builtin_va_arg (valist, svint8_t); + + // Other built-ins + + __builtin_launder (sve_sc1); // { dg-error {non-pointer argument to '__builtin_launder'} } + __builtin_memcpy (&sve_sc1, &sve_sc2, 2); + + // Lambdas + +#if __cplusplus >= 201103L + [sve_sc1] () {}; // { dg-error {capture by copy of SVE type 'svint8_t'} "" { target c++11 } } + [=] () { &sve_sc1; }; // { dg-error {capture by copy of SVE type 'svint8_t'} "" { target c++11 } } + [&sve_sc1] () { sve_sc1 = sve_sc2; }; // { dg-error {'sve_sc2' is not captured} "" { target c++11 } } + [&sve_sc1, &sve_sc2] () { sve_sc1 = sve_sc2; }; + [&] () { sve_sc1 = sve_sc2; }; + [] () { return ext_produce_sve_sc (); } (); +#endif + + // Exceptions + + throw svint8_t (); // { dg-error {cannot throw or catch SVE type 'svint8_t'} } + try {} catch (svint8_t x) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} } + try {} catch (svint8_t &x) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} } + try {} catch (svint8_t *x) {} +#if __cplusplus < 201103L + thrower2 (); +#endif + + // Use in traits. Doesn't use static_assert so that tests work with + // earlier -std=s. + + { typedef int f[__has_nothrow_assign (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_assign (svint8_t) ? 1 : -1]; } + { typedef int f[__has_nothrow_constructor (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_constructor (svint8_t) ? 1 : -1]; } + { typedef int f[__has_nothrow_copy (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_copy (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_destructor (svint8_t) ? 1 : -1]; } + { typedef int f[__has_unique_object_representations (svint8_t) ? 1 : -1]; } + { typedef int f[!__has_virtual_destructor (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_abstract (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_aggregate (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_base_of (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_base_of (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[!__is_class (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_empty (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_enum (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_final (svint8_t) ? 1 : -1]; } + { typedef int f[__is_pod (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_polymorphic (svint8_t) ? 1 : -1]; } + { typedef int f[__is_same_as (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[__is_same_as (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[__is_same_as (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[__is_same_as (svint8_t *, svint8_t *) ? 1 : -1]; } + { typedef int f[__is_same_as (svint8_t *, int8x32_t *) ? 1 : -1]; } + { typedef int f[__is_same_as (int8x32_t *, svint8_t *) ? 1 : -1]; } + { typedef int f[!__is_same_as (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_same_as (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[__is_trivial (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_union (svint8_t) ? 1 : -1]; } + { typedef int f[__is_trivially_copyable (svint8_t) ? 1 : -1]; } + /* The intention is that svint8_t should behave like int8x32_t here. If the behavior + for int8x32_t changes then the behavior for svint8_t should change in the same + way. */ + { typedef int f[!__is_trivially_assignable (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (svint8_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_constructible (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_trivially_constructible (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[__is_constructible (svint8_t) ? 1 : -1]; } + { typedef int f[__is_constructible (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[__is_constructible (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[__is_constructible (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[__is_constructible (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_constructible (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_constructible (svint8_t, svint16_t) ? 1 : -1]; } +} + +// Function parameters in definitions. + +void +unnamed_st1 (svint8_t) +{ +} + +void +named_st1 (svint8_t param1) +{ + svint8_t sve_sc1 = param1; +} + +// Function return values in definitions. + +svint8_t +ret_st1 (svint8_t param) +{ + return param; +} + +svint8_t +bad_ret_st1 (svint16_t param) +{ + return param; // { dg-error {cannot convert 'svint16_t' to 'svint8_t' in return} } +} + +#if __cplusplus >= 201103L +template<typename T> +void +const_to_sve_sc (T i) +{ + constexpr svint8_t a = (svint8_t) i; +} +#endif + +template<typename T> +int +get_x (T *a) +{ + return a->a; // { dg-error {request for member 'a' in '\* a', which is of non-class type} } +} +template int get_x<svint8_t>(svint8_t *); + +#if __cplusplus < 201103L +void thrower3 () throw (svint8_t) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +#endif + +// Using "auto" as a return type. + +#if __cplusplus >= 201402L +auto auto_ret_sve_sc (svint8_t *ptr) { return *ptr; } +const auto &auto_ret_const_sve_sc_ref (svint8_t *ptr) { return *ptr; } +auto &auto_ret_sve_sc_ref (svint8_t *ptr) { return *ptr; } +auto &&auto_ret_sve_sc_rvalue_ref (svint8_t *ptr) { return *ptr; } +#endif
On 12/6/19 9:26 AM, Richard Sandiford wrote: > Jason Merrill <jason@redhat.com> writes: >> On 12/5/19 1:21 PM, Richard Sandiford wrote: >>> + else if (!verify_type_context (input_location, TCTX_EXCEPTIONS, type)) >>> + return false; >>> + >>> + else if (TYPE_REF_P (type) >>> + && !verify_type_context (input_location, TCTX_EXCEPTIONS, >>> + TREE_TYPE (type))) >> >> You could use the non_reference function to combine these. > > Thanks. This patch fixes that and follows Marek's suggestion of using > location_of in check_array_initializer. (I wondered whether to check > for decl == error_mark_node as well, but that can't currently happen.) > > Tested on aarch64-linux-gnu and x86_64-linux-gnu. OK to install? OK. > Richard > > > 2019-12-06 Richard Sandiford <richard.sandiford@arm.com> > > gcc/ > * target.h (TCTX_ALLOCATION, TCTX_DEALLOCATION, TCTX_EXCEPTIONS) > (TCTX_CAPTURE_BY_COPY): New type_context_kinds. > * config/aarch64/aarch64-sve-builtins.cc (verify_type_context): > Handle them. > > gcc/cp/ > * decl.c (start_decl_1): Use verify_type_context to check whether > the target allows variables of a particular type to have static > or thread-local storage duration. > (check_array_initializer): Use verify_type_context to check whether > the target allows a particular type to be used as an array element. > (create_array_type_for_decl): Likewise. > (cp_finish_decl): Use verify_type_context to check whether > the target allows static member variables of a particular type. > (grokdeclarator): Likewise. Also use verify_type_context to check > whether the target allows non-static member variables of a particular > type. > * except.c: Include target.h. > (is_admissible_throw_operand_or_catch_parameter): Use > verify_type_context to check whether the target allows particular > types to be thrown and caught. > * typeck2.c (add_exception_specifier): Likewise. > * init.c (build_new_1): Use verify_type_context to check whether > the target allows particular types to be dynamically allocated. > (build_vec_delete_1, build_delete): Use verify_type_context to check > whether the target allows particular types to be deleted. > * lambda.c (add_capture): Use verify_type_context to check > whether the target allows particular types to be captured by copy. > * pt.c: Include target.h. > (instantiate_class_template_1): Use verify_type_context to check > whether the target allows non-static member variables of a particular > type. > * typeck.c (cxx_alignof_expr): Use verify_type_context to check > whether the target allows the alignment of a particular type > to be measured. > (pointer_diff, cp_build_unary_op): Use verify_type_context to check > whether the target allows arithmetic involving pointers to particular > types. > > gcc/testsuite/ > * g++.dg/ext/sve-sizeless-1.C: New test. > * g++.dg/ext/sve-sizeless-2.C: Likewise. > > Index: gcc/target.h > =================================================================== > --- gcc/target.h 2019-12-04 13:13:48.000000000 +0000 > +++ gcc/target.h 2019-12-06 14:11:28.233552680 +0000 > @@ -249,7 +249,19 @@ enum type_context_kind { > > /* 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 > + TCTX_POINTER_ARITH, > + > + /* Dynamically allocating objects of type T. */ > + TCTX_ALLOCATION, > + > + /* Dynamically deallocating objects of type T. */ > + TCTX_DEALLOCATION, > + > + /* Throwing or catching an object of type T. */ > + TCTX_EXCEPTIONS, > + > + /* Capturing objects of type T by value in a closure. */ > + TCTX_CAPTURE_BY_COPY > }; > > extern bool verify_type_context (location_t, type_context_kind, const_tree, > Index: gcc/config/aarch64/aarch64-sve-builtins.cc > =================================================================== > --- gcc/config/aarch64/aarch64-sve-builtins.cc 2019-12-04 13:13:48.000000000 +0000 > +++ gcc/config/aarch64/aarch64-sve-builtins.cc 2019-12-06 14:11:28.217552787 +0000 > @@ -3352,6 +3352,26 @@ verify_type_context (location_t loc, typ > if (!silent_p) > error_at (loc, "array elements cannot have SVE type %qT", type); > return false; > + > + case TCTX_ALLOCATION: > + if (!silent_p) > + error_at (loc, "cannot allocate objects with SVE type %qT", type); > + return false; > + > + case TCTX_DEALLOCATION: > + if (!silent_p) > + error_at (loc, "cannot delete objects with SVE type %qT", type); > + return false; > + > + case TCTX_EXCEPTIONS: > + if (!silent_p) > + error_at (loc, "cannot throw or catch SVE type %qT", type); > + return false; > + > + case TCTX_CAPTURE_BY_COPY: > + if (!silent_p) > + error_at (loc, "capture by copy of SVE type %qT", type); > + return false; > } > gcc_unreachable (); > } > Index: gcc/cp/decl.c > =================================================================== > --- gcc/cp/decl.c 2019-12-06 10:31:11.638430940 +0000 > +++ gcc/cp/decl.c 2019-12-06 14:11:28.221552762 +0000 > @@ -5470,6 +5470,13 @@ start_decl_1 (tree decl, bool initialize > cp_apply_type_quals_to_decl (cp_type_quals (type), decl); > } > > + if (is_global_var (decl)) > + { > + type_context_kind context = (DECL_THREAD_LOCAL_P (decl) > + ? TCTX_THREAD_STORAGE > + : TCTX_STATIC_STORAGE); > + verify_type_context (input_location, context, TREE_TYPE (decl)); > + } > if (initialized) > /* Is it valid for this decl to have an initializer at all? */ > { > @@ -6535,6 +6542,11 @@ check_array_initializer (tree decl, tree > error ("elements of array %q#T have incomplete type", type); > return true; > } > + > + location_t loc = (decl ? location_of (decl) : input_location); > + if (!verify_type_context (loc, TCTX_ARRAY_ELEMENT, element_type)) > + return true; > + > /* A compound literal can't have variable size. */ > if (init && !decl > && ((COMPLETE_TYPE_P (type) && !TREE_CONSTANT (TYPE_SIZE (type))) > @@ -7482,6 +7494,8 @@ cp_finish_decl (tree decl, tree init, bo > > if (VAR_P (decl) > && DECL_CLASS_SCOPE_P (decl) > + && verify_type_context (DECL_SOURCE_LOCATION (decl), > + TCTX_STATIC_STORAGE, type) > && DECL_INITIALIZED_IN_CLASS_P (decl)) > check_static_variable_definition (decl, type); > > @@ -10550,6 +10564,10 @@ create_array_type_for_decl (tree name, t > break; > } > > + if (!verify_type_context (name ? loc : input_location, > + TCTX_ARRAY_ELEMENT, type)) > + return error_mark_node; > + > /* [dcl.array] > > The constant expressions that specify the bounds of the arrays > @@ -13254,6 +13272,14 @@ grokdeclarator (const cp_declarator *dec > decl = NULL_TREE; > } > } > + else if (!verify_type_context (input_location, > + staticp > + ? TCTX_STATIC_STORAGE > + : TCTX_FIELD, type)) > + { > + type = error_mark_node; > + decl = NULL_TREE; > + } > else > { > if (friendp) > Index: gcc/cp/except.c > =================================================================== > --- gcc/cp/except.c 2019-12-04 13:13:48.000000000 +0000 > +++ gcc/cp/except.c 2019-12-06 14:11:28.221552762 +0000 > @@ -29,6 +29,7 @@ the Free Software Foundation; either ver > #include "trans-mem.h" > #include "attribs.h" > #include "tree-iterator.h" > +#include "target.h" > > static void push_eh_cleanup (tree); > static tree prepare_eh_type (tree); > @@ -927,6 +928,10 @@ is_admissible_throw_operand_or_catch_par > if (!complete_ptr_ref_or_void_ptr_p (type, expr)) > return false; > > + tree nonref_type = non_reference (type); > + if (!verify_type_context (input_location, TCTX_EXCEPTIONS, nonref_type)) > + return false; > + > /* 10.4/3 An abstract class shall not be used as a parameter type, > as a function return type or as type of an explicit > conversion. */ > Index: gcc/cp/typeck2.c > =================================================================== > --- gcc/cp/typeck2.c 2019-12-05 14:20:16.965063368 +0000 > +++ gcc/cp/typeck2.c 2019-12-06 14:11:28.233552680 +0000 > @@ -33,6 +33,7 @@ the Free Software Foundation; either ver > #include "varasm.h" > #include "intl.h" > #include "gcc-rich-location.h" > +#include "target.h" > > static tree > process_init_constructor (tree type, tree init, int nested, int flags, > @@ -2401,6 +2402,9 @@ add_exception_specifier (tree list, tree > ok = true; > else if (processing_template_decl) > ok = true; > + else if (!verify_type_context (input_location, TCTX_EXCEPTIONS, core, > + !(complain & tf_error))) > + return error_mark_node; > else > { > ok = true; > Index: gcc/cp/init.c > =================================================================== > --- gcc/cp/init.c 2019-12-04 13:13:48.000000000 +0000 > +++ gcc/cp/init.c 2019-12-06 14:11:28.221552762 +0000 > @@ -3058,6 +3058,10 @@ build_new_1 (vec<tree, va_gc> **placemen > complain); > } > > + if (!verify_type_context (input_location, TCTX_ALLOCATION, elt_type, > + !(complain & tf_error))) > + return error_mark_node; > + > if (variably_modified_type_p (elt_type, NULL_TREE) && (complain & tf_error)) > { > error ("variably modified type not allowed in new-expression"); > @@ -3942,6 +3946,10 @@ build_vec_delete_1 (tree base, tree maxi > if (base == error_mark_node || maxindex == error_mark_node) > return error_mark_node; > > + if (!verify_type_context (input_location, TCTX_DEALLOCATION, type, > + !(complain & tf_error))) > + return error_mark_node; > + > if (!COMPLETE_TYPE_P (type)) > { > if (complain & tf_warning) > @@ -4827,6 +4835,11 @@ build_delete (tree otype, tree addr, spe > if (!VOID_TYPE_P (type)) > { > complete_type (type); > + if (deleting > + && !verify_type_context (input_location, TCTX_DEALLOCATION, type, > + !(complain & tf_error))) > + return error_mark_node; > + > if (!COMPLETE_TYPE_P (type)) > { > if (complain & tf_warning) > Index: gcc/cp/lambda.c > =================================================================== > --- gcc/cp/lambda.c 2019-12-04 13:13:48.000000000 +0000 > +++ gcc/cp/lambda.c 2019-12-06 14:11:28.225552732 +0000 > @@ -30,6 +30,7 @@ > #include "tree-iterator.h" > #include "toplev.h" > #include "gimplify.h" > +#include "target.h" > > /* Constructor for a lambda expression. */ > > @@ -579,6 +580,9 @@ add_capture (tree lambda, tree id, tree > cxx_incomplete_type_inform (type); > return error_mark_node; > } > + else if (!verify_type_context (input_location, > + TCTX_CAPTURE_BY_COPY, type)) > + return error_mark_node; > } > } > > Index: gcc/cp/pt.c > =================================================================== > --- gcc/cp/pt.c 2019-12-05 14:20:16.969063342 +0000 > +++ gcc/cp/pt.c 2019-12-06 14:11:28.229552706 +0000 > @@ -42,6 +42,7 @@ the Free Software Foundation; either ver > #include "gimplify.h" > #include "gcc-rich-location.h" > #include "selftest.h" > +#include "target.h" > > /* The type of functions taking a tree, and some additional data, and > returning an int. */ > @@ -11815,6 +11816,9 @@ instantiate_class_template_1 (tree type) > error ("flexible array member %qD in union", r); > TREE_TYPE (r) = error_mark_node; > } > + else if (!verify_type_context (input_location, > + TCTX_FIELD, rtype)) > + TREE_TYPE (r) = error_mark_node; > } > > /* If it is a TYPE_DECL for a class-scoped ENUMERAL_TYPE, > Index: gcc/cp/typeck.c > =================================================================== > --- gcc/cp/typeck.c 2019-12-04 13:13:48.000000000 +0000 > +++ gcc/cp/typeck.c 2019-12-06 14:11:28.229552706 +0000 > @@ -1824,7 +1824,14 @@ cxx_alignof_expr (tree e, tsubst_flags_t > > e = mark_type_use (e); > > - if (VAR_P (e)) > + if (!verify_type_context (input_location, TCTX_ALIGNOF, TREE_TYPE (e), > + !(complain & tf_error))) > + { > + if (!(complain & tf_error)) > + return error_mark_node; > + t = size_one_node; > + } > + else if (VAR_P (e)) > t = size_int (DECL_ALIGN_UNIT (e)); > else if (bitfield_p (e)) > { > @@ -5778,6 +5785,13 @@ pointer_diff (location_t loc, tree op0, > else > return error_mark_node; > } > + else if (!verify_type_context (loc, TCTX_POINTER_ARITH, > + TREE_TYPE (TREE_TYPE (op0)), > + !(complain & tf_error)) > + || !verify_type_context (loc, TCTX_POINTER_ARITH, > + TREE_TYPE (TREE_TYPE (op1)), > + !(complain & tf_error))) > + return error_mark_node; > > /* Determine integer type result of the subtraction. This will usually > be the same as the result type (ptrdiff_t), but may need to be a wider > @@ -6572,6 +6586,10 @@ cp_build_unary_op (enum tree_code code, > else > return error_mark_node; > } > + else if (!verify_type_context (location, TCTX_POINTER_ARITH, > + TREE_TYPE (argtype), > + !(complain & tf_error))) > + return error_mark_node; > > inc = cxx_sizeof_nowarn (TREE_TYPE (argtype)); > } > Index: gcc/testsuite/g++.dg/ext/sve-sizeless-1.C > =================================================================== > --- /dev/null 2019-09-17 11:41:18.176664108 +0100 > +++ gcc/testsuite/g++.dg/ext/sve-sizeless-1.C 2019-12-06 14:11:28.233552680 +0000 > @@ -0,0 +1,420 @@ > +// { dg-do compile { target aarch64*-*-* } } > +// { dg-options "-Wclass-memaccess" } > + > +#pragma GCC target "+sve" > + > +typedef __SIZE_TYPE__ size_t; > +inline void *operator new (size_t, void *__p) throw() { return __p; } > + > +#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} } > + > +// 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 member variables. > + > +struct struct1 { > + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } > +}; > + > +union union1 { > + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } > +}; > + > +#if __cplusplus >= 201103L > +struct static_sve_sc { > + static svint8_t sve_sc1 = {}; // { dg-error {SVE type 'svint8_t' does not have a fixed size} "" { target c++11 } } > +}; > +#endif > + > +// Sizeless member variables in templated structures. > + > +template<typename T> > +struct templated_struct1 { > + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } > +}; > + > +template<typename T> > +struct templated_struct2 { > + T a; // { dg-error {member variables cannot have SVE type '(svint8_t|__SVInt8_t)'} } > +}; > + > +template class templated_struct2<svint8_t>; > + > +template<typename T> > +struct templated_struct3 { > + T &a; > +}; > + > +template class templated_struct3<svint8_t>; > + > +#if __cplusplus >= 201103L > +template<typename T> > +struct templated_struct4 { > + static T a; // { dg-error {SVE type '(svint8_t|__SVInt8_t)' does not have a fixed size} "" { target c++11 } } > + static T b = {}; // { dg-error {SVE type '(svint8_t|__SVInt8_t)' does not have a fixed size} "" { target c++11 } } > +}; > + > +template class templated_struct4<svint8_t>; > +#endif > + > +template<typename T> struct templated_struct5 : T {}; // { dg-error {base type '[^']*' fails to be a struct or class type} } > +template class templated_struct5<svint8_t>; > + > +#if __cplusplus >= 201103L > +template<int N> using typedef_sizeless1 = svint8_t; > +template<int N> using typedef_sizeless1 = svint8_t; // { dg-error {redefinition of 'template<int N> using typedef_sizeless1 = svint8_t'} "" { target c++11 } } > +template<typename T> using array = T[2]; > +#endif > + > +// Pointers to sizeless types. > + > +svint8_t *global_sve_sc_ptr; > + > +// Sizeless arguments and return values. > + > +void ext_consume_sve_sc (svint8_t); > +void ext_consume_const_int_ref (const int &); > +void ext_consume_varargs (int, ...); > +svint8_t ext_produce_sve_sc (); > + > +// Sizeless types in throw specifications. > + > +#if __cplusplus < 201103L > +void thrower1 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } > +void thrower2 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } > +void thrower3 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } > +#endif > + > +// Main tests for statements and expressions. > + > +void > +statements (int n) > +{ > + // Local declarations. > + > + svint8_t sve_sc1, sve_sc2; > + volatile svint8_t volatile_sve_sc1; > + int8x32_t gnu_sc1; > + svint16_t sve_sh1; > + > + // 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} } > + > +#if __cplusplus >= 201103L > + array<svint8_t> foo = {}; // { dg-error {array elements cannot have SVE type '(svint8_t|__SVInt8_t)'} "" { target c++11 } } > +#endif > + > + // Initialization. > + > + int init_int1 = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } > + int init_int2 = { sve_sc1 }; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } > + > + svint8_t init_sve_sc1 (sve_sc1); > + svint8_t init_sve_sc2 (sve_sh1); // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } > + svint8_t init_sve_sc3 = sve_sc1; > + svint8_t init_sve_sc4 = sve_sh1; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } > + svint8_t init_sve_sc5 = {}; > + svint8_t init_sve_sc6 = { sve_sc1 }; > + svint8_t init_sve_sc7 = { sve_sh1 }; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } > + > + // Constructor calls. > + > + (0, svint8_t ()); > + > + // Lvalue reference binding > + > + svint8_t &lvalue_ref_sve_sc1 = sve_sc1; > + svint8_t &lvalue_ref_sve_sc2 = ext_produce_sve_sc (); // { dg-error {cannot bind non-const lvalue reference of type 'svint8_t&' to an rvalue of type 'svint8_t'} } > + svint8_t &lvalue_ref_sve_sc3 = sve_sh1; // { dg-error {invalid initialization of reference of type 'svint8_t&' from expression of type 'svint16_t'} } > + > + const svint8_t &const_lvalue_ref_sve_sc1 = sve_sc1; > + const svint8_t &const_lvalue_ref_sve_sc2 = ext_produce_sve_sc (); > + const svint8_t &const_lvalue_ref_sve_sc3 = sve_sh1; // { dg-error {invalid initialization of reference of type 'const svint8_t&' from expression of type 'svint16_t'} } > + > + // Compound literals. > + > + (int) { sve_sc1 }; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } > + > + // 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'} } > + > + // Assignment. > + > + n = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int' in assignment} } > + > + sve_sc1 = 0; // { dg-error {cannot convert 'int' to 'svint8_t' in assignment} } > + sve_sc1 = sve_sc1; > + sve_sc1 = gnu_sc1; // { dg-error {cannot convert 'int8x32_t'[^\n]* to 'svint8_t' in assignment} } > + gnu_sc1 = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int8x32_t'} } > + sve_sc1 = sve_sh1; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } > + > + // Casting. > + > + (void) sve_sc1; > + (void) volatile_sve_sc1; > + (void) *&volatile_sve_sc1; > + > + // Addressing and dereferencing. > + > + svint8_t *sve_sc_ptr = &sve_sc1; > + int8x32_t *gnu_sc_ptr = &gnu_sc1; > + sve_sc_ptr = (svint16_t *) 0; // { dg-error {cannot convert 'svint16_t\*' to 'svint8_t\*' in assignment} } > + > + // Pointer assignment. > + > + gnu_sc_ptr = sve_sc_ptr; // { dg-error {cannot convert 'svint8_t\*' to 'int8x32_t\*'} } > + sve_sc_ptr = gnu_sc_ptr; // { dg-error {cannot convert 'int8x32_t\*'[^\n]* to 'svint8_t\*'} } > + > + // 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 of types 'int8x32_t\*'[^\n]* and 'svint8_t\*' to binary 'operator-'} } > + sve_sc_ptr - gnu_sc_ptr; // { dg-error {invalid operands of types 'svint8_t\*' and 'int8x32_t\*'[^\n]* to binary 'operator-'} } > + 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-error {comparison between distinct pointer types [^\n]*lacks a cast} } > + gnu_sc_ptr != sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } > + gnu_sc_ptr < sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } > + gnu_sc_ptr <= sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } > + gnu_sc_ptr > sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } > + gnu_sc_ptr >= sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } > + sve_sc_ptr == gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } > + sve_sc_ptr != gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } > + sve_sc_ptr < gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } > + sve_sc_ptr <= gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } > + sve_sc_ptr > gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } > + sve_sc_ptr >= gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } > + > + // New and delete. > + > + new svint8_t; // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } > + new svint8_t (); // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } > + > + new (global_sve_sc_ptr) svint8_t; // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } > + new (global_sve_sc_ptr) svint8_t (); // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } > + > + sve_sc1.~svint8_t(); // { dg-error {expected class-name before '\(' token} } > + delete sve_sc_ptr; // { dg-error {cannot delete objects with SVE type '(svint8_t|__SVInt8_t)'} } > + delete[] sve_sc_ptr; // { dg-error {cannot delete objects with SVE type 'svint8_t'} } > + > + // Conditional expressions. > + > + 0 ? sve_sc1 : sve_sc1; > + 0 ? sve_sc1 : sve_sh1; // { dg-error {different types 'svint8_t' and 'svint16_t'} } > + 0 ? sve_sc1 : 0; // { dg-error {different types 'svint8_t' and 'int'} } > + 0 ? 0 : sve_sc1; // { dg-error {different types 'int' and 'svint8_t'} } > + 0 ? sve_sc1 : sve_sc1; > + 0 ? sve_sc_ptr : sve_sc_ptr; > + 0 ? sve_sc_ptr : gnu_sc_ptr; // { dg-error {conditional expression between distinct pointer types [^\n]*lacks a cast} } > + 0 ? gnu_sc_ptr : sve_sc_ptr; // { dg-error {conditional expression between distinct pointer types [^\n]*lacks a cast} } > + > + // Function arguments. > + > + ext_consume_sve_sc (sve_sc1); > + ext_consume_sve_sc (sve_sh1); // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } > + ext_consume_const_int_ref (sve_sc1); // { dg-error {invalid initialization of reference of type 'const int&' from expression of type 'svint8_t'} } > + ext_consume_varargs (sve_sc1); // { dg-error {cannot convert 'svint8_t' to 'int'} } > + 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 {cannot convert 'svint8_t' to 'svint16_t' in assignment} } > + > + // Auto > + > +#if __cplusplus >= 201103L > + auto auto_sve_sc1 = sve_sc1; > + auto auto_sve_sc1_return = ext_produce_sve_sc (); > +#endif > + > + // Varargs processing. > + > + __builtin_va_list valist; > + __builtin_va_arg (valist, svint8_t); > + > + // Other built-ins > + > + __builtin_launder (sve_sc1); // { dg-error {non-pointer argument to '__builtin_launder'} } > + __builtin_memcpy (&sve_sc1, &sve_sc2, 2); > + > + // Lambdas > + > +#if __cplusplus >= 201103L > + [sve_sc1] () {}; // { dg-error {capture by copy of SVE type 'svint8_t'} "" { target c++11 } } > + [=] () { &sve_sc1; }; // { dg-error {capture by copy of SVE type 'svint8_t'} "" { target c++11 } } > + [&sve_sc1] () { sve_sc1 = sve_sc2; }; // { dg-error {'sve_sc2' is not captured} "" { target c++11 } } > + [&sve_sc1, &sve_sc2] () { sve_sc1 = sve_sc2; }; > + [&] () { sve_sc1 = sve_sc2; }; > + [] () { return ext_produce_sve_sc (); } (); > +#endif > + > + // Exceptions > + > + throw svint8_t (); // { dg-error {cannot throw or catch SVE type 'svint8_t'} } > + try {} catch (svint8_t x) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} } > + try {} catch (svint8_t &x) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} } > + try {} catch (svint8_t *x) {} > +#if __cplusplus < 201103L > + thrower2 (); > +#endif > + > + // Use in traits. Doesn't use static_assert so that tests work with > + // earlier -std=s. > + > + { typedef int f[__has_nothrow_assign (svint8_t) ? 1 : -1]; } > + { typedef int f[__has_trivial_assign (svint8_t) ? 1 : -1]; } > + { typedef int f[__has_nothrow_constructor (svint8_t) ? 1 : -1]; } > + { typedef int f[__has_trivial_constructor (svint8_t) ? 1 : -1]; } > + { typedef int f[__has_nothrow_copy (svint8_t) ? 1 : -1]; } > + { typedef int f[__has_trivial_copy (svint8_t) ? 1 : -1]; } > + { typedef int f[__has_trivial_destructor (svint8_t) ? 1 : -1]; } > + { typedef int f[__has_unique_object_representations (svint8_t) ? 1 : -1]; } > + { typedef int f[!__has_virtual_destructor (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_abstract (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_aggregate (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_base_of (svint8_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_base_of (svint8_t, svint16_t) ? 1 : -1]; } > + { typedef int f[!__is_class (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_empty (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_enum (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_final (svint8_t) ? 1 : -1]; } > + { typedef int f[__is_pod (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_polymorphic (svint8_t) ? 1 : -1]; } > + { typedef int f[__is_same_as (svint8_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_same_as (svint8_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[!__is_same_as (int8x32_t, svint8_t) ? 1 : -1]; } > + { typedef int f[__is_same_as (svint8_t *, svint8_t *) ? 1 : -1]; } > + { typedef int f[!__is_same_as (svint8_t *, int8x32_t *) ? 1 : -1]; } > + { typedef int f[!__is_same_as (int8x32_t *, svint8_t *) ? 1 : -1]; } > + { typedef int f[!__is_same_as (svint8_t, int) ? 1 : -1]; } > + { typedef int f[!__is_same_as (svint8_t, svint16_t) ? 1 : -1]; } > + { typedef int f[__is_trivial (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_union (svint8_t) ? 1 : -1]; } > + { typedef int f[__is_trivially_copyable (svint8_t) ? 1 : -1]; } > + /* The intention is that svint8_t should behave like int8x32_t here. If the behavior > + for int8x32_t changes then the behavior for svint8_t should change in the same > + way. */ > + { typedef int f[!__is_trivially_assignable (int8x32_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[!__is_trivially_assignable (svint8_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_trivially_assignable (svint8_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[!__is_trivially_assignable (int8x32_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_trivially_assignable (svint8_t, int) ? 1 : -1]; } > + { typedef int f[!__is_trivially_assignable (svint8_t, svint16_t) ? 1 : -1]; } > + { typedef int f[!__is_assignable (int8x32_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[!__is_assignable (svint8_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_assignable (svint8_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[!__is_assignable (int8x32_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_assignable (svint8_t, int) ? 1 : -1]; } > + { typedef int f[!__is_assignable (svint8_t, svint16_t) ? 1 : -1]; } > + { typedef int f[__is_trivially_constructible (svint8_t) ? 1 : -1]; } > + { typedef int f[__is_trivially_constructible (int8x32_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[__is_trivially_constructible (svint8_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_trivially_constructible (svint8_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[!__is_trivially_constructible (int8x32_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_trivially_constructible (svint8_t, int) ? 1 : -1]; } > + { typedef int f[!__is_trivially_constructible (svint8_t, svint16_t) ? 1 : -1]; } > + { typedef int f[__is_constructible (svint8_t) ? 1 : -1]; } > + { typedef int f[__is_constructible (int8x32_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[__is_constructible (svint8_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_constructible (svint8_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[!__is_constructible (int8x32_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_constructible (svint8_t, int) ? 1 : -1]; } > + { typedef int f[!__is_constructible (svint8_t, svint16_t) ? 1 : -1]; } > +} > + > +// Function parameters in definitions. > + > +void > +unnamed_st1 (svint8_t) > +{ > +} > + > +void > +named_st1 (svint8_t param1) > +{ > + svint8_t sve_sc1 = param1; > +} > + > +// Function return values in definitions. > + > +svint8_t > +ret_st1 (svint8_t param) > +{ > + return param; > +} > + > +svint8_t > +bad_ret_st1 (svint16_t param) > +{ > + return param; // { dg-error {cannot convert 'svint16_t' to 'svint8_t' in return} } > +} > + > +#if __cplusplus >= 201103L > +template<typename T> > +void > +const_to_sve_sc (T i) > +{ > + constexpr svint8_t a = (svint8_t) i; > +} > +#endif > + > +template<typename T> > +int > +get_x (T *a) > +{ > + return a->a; // { dg-error {request for member 'a' in '\* a', which is of non-class type} } > +} > +template int get_x<svint8_t>(svint8_t *); > + > +#if __cplusplus < 201103L > +void thrower3 () throw (svint8_t) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } > +#endif > + > +// Using "auto" as a return type. > + > +#if __cplusplus >= 201402L > +auto auto_ret_sve_sc (svint8_t *ptr) { return *ptr; } > +const auto &auto_ret_const_sve_sc_ref (svint8_t *ptr) { return *ptr; } > +auto &auto_ret_sve_sc_ref (svint8_t *ptr) { return *ptr; } > +auto &&auto_ret_sve_sc_rvalue_ref (svint8_t *ptr) { return *ptr; } > +#endif > Index: gcc/testsuite/g++.dg/ext/sve-sizeless-2.C > =================================================================== > --- /dev/null 2019-09-17 11:41:18.176664108 +0100 > +++ gcc/testsuite/g++.dg/ext/sve-sizeless-2.C 2019-12-06 14:11:28.233552680 +0000 > @@ -0,0 +1,420 @@ > +// { dg-do compile { target aarch64*-*-* } } > +// { dg-options "-Wclass-memaccess -msve-vector-bits=256" } > + > +#pragma GCC target "+sve" > + > +typedef __SIZE_TYPE__ size_t; > +inline void *operator new (size_t, void *__p) throw() { return __p; } > + > +#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} } > + > +// 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 member variables. > + > +struct struct1 { > + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } > +}; > + > +union union1 { > + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } > +}; > + > +#if __cplusplus >= 201103L > +struct static_sve_sc { > + static svint8_t sve_sc1 = {}; // { dg-error {SVE type 'svint8_t' does not have a fixed size} "" { target c++11 } } > +}; > +#endif > + > +// Sizeless member variables in templated structures. > + > +template<typename T> > +struct templated_struct1 { > + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } > +}; > + > +template<typename T> > +struct templated_struct2 { > + T a; // { dg-error {member variables cannot have SVE type '(svint8_t|__SVInt8_t)'} } > +}; > + > +template class templated_struct2<svint8_t>; > + > +template<typename T> > +struct templated_struct3 { > + T &a; > +}; > + > +template class templated_struct3<svint8_t>; > + > +#if __cplusplus >= 201103L > +template<typename T> > +struct templated_struct4 { > + static T a; // { dg-error {SVE type '(svint8_t|__SVInt8_t)' does not have a fixed size} "" { target c++11 } } > + static T b = {}; // { dg-error {SVE type '(svint8_t|__SVInt8_t)' does not have a fixed size} "" { target c++11 } } > +}; > + > +template class templated_struct4<svint8_t>; > +#endif > + > +template<typename T> struct templated_struct5 : T {}; // { dg-error {base type '[^']*' fails to be a struct or class type} } > +template class templated_struct5<svint8_t>; > + > +#if __cplusplus >= 201103L > +template<int N> using typedef_sizeless1 = svint8_t; > +template<int N> using typedef_sizeless1 = svint8_t; // { dg-error {redefinition of 'template<int N> using typedef_sizeless1 = svint8_t'} "" { target c++11 } } > +template<typename T> using array = T[2]; > +#endif > + > +// Pointers to sizeless types. > + > +svint8_t *global_sve_sc_ptr; > + > +// Sizeless arguments and return values. > + > +void ext_consume_sve_sc (svint8_t); > +void ext_consume_const_int_ref (const int &); > +void ext_consume_varargs (int, ...); > +svint8_t ext_produce_sve_sc (); > + > +// Sizeless types in throw specifications. > + > +#if __cplusplus < 201103L > +void thrower1 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } > +void thrower2 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } > +void thrower3 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } > +#endif > + > +// Main tests for statements and expressions. > + > +void > +statements (int n) > +{ > + // Local declarations. > + > + svint8_t sve_sc1, sve_sc2; > + volatile svint8_t volatile_sve_sc1; > + int8x32_t gnu_sc1; > + svint16_t sve_sh1; > + > + // 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} } > + > +#if __cplusplus >= 201103L > + array<svint8_t> foo = {}; // { dg-error {array elements cannot have SVE type '(svint8_t|__SVInt8_t)'} "" { target c++11 } } > +#endif > + > + // Initialization. > + > + int init_int1 = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } > + int init_int2 = { sve_sc1 }; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } > + > + svint8_t init_sve_sc1 (sve_sc1); > + svint8_t init_sve_sc2 (sve_sh1); // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } > + svint8_t init_sve_sc3 = sve_sc1; > + svint8_t init_sve_sc4 = sve_sh1; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } > + svint8_t init_sve_sc5 = {}; > + svint8_t init_sve_sc6 = { sve_sc1 }; > + svint8_t init_sve_sc7 = { sve_sh1 }; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } > + > + // Constructor calls. > + > + (0, svint8_t ()); > + > + // Lvalue reference binding > + > + svint8_t &lvalue_ref_sve_sc1 = sve_sc1; > + svint8_t &lvalue_ref_sve_sc2 = ext_produce_sve_sc (); // { dg-error {cannot bind non-const lvalue reference of type 'svint8_t&' to an rvalue of type 'svint8_t'} } > + svint8_t &lvalue_ref_sve_sc3 = sve_sh1; // { dg-error {invalid initialization of reference of type 'svint8_t&' from expression of type 'svint16_t'} } > + > + const svint8_t &const_lvalue_ref_sve_sc1 = sve_sc1; > + const svint8_t &const_lvalue_ref_sve_sc2 = ext_produce_sve_sc (); > + const svint8_t &const_lvalue_ref_sve_sc3 = sve_sh1; // { dg-error {invalid initialization of reference of type 'const svint8_t&' from expression of type 'svint16_t'} } > + > + // Compound literals. > + > + (int) { sve_sc1 }; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } > + > + // 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'} } > + > + // Assignment. > + > + n = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int' in assignment} } > + > + sve_sc1 = 0; // { dg-error {cannot convert 'int' to 'svint8_t' in assignment} } > + sve_sc1 = sve_sc1; > + sve_sc1 = gnu_sc1; > + gnu_sc1 = sve_sc1; > + sve_sc1 = sve_sh1; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } > + > + // Casting. > + > + (void) sve_sc1; > + (void) volatile_sve_sc1; > + (void) *&volatile_sve_sc1; > + > + // Addressing and dereferencing. > + > + svint8_t *sve_sc_ptr = &sve_sc1; > + int8x32_t *gnu_sc_ptr = &gnu_sc1; > + sve_sc_ptr = (svint16_t *) 0; // { dg-error {cannot convert 'svint16_t\*' to 'svint8_t\*' in assignment} } > + > + // 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; > + > + // New and delete. > + > + new svint8_t; // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } > + new svint8_t (); // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } > + > + new (global_sve_sc_ptr) svint8_t; // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } > + new (global_sve_sc_ptr) svint8_t (); // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } > + > + sve_sc1.~svint8_t(); // { dg-error {expected class-name before '\(' token} } > + delete sve_sc_ptr; // { dg-error {cannot delete objects with SVE type '(svint8_t|__SVInt8_t)'} } > + delete[] sve_sc_ptr; // { dg-error {cannot delete objects with SVE type 'svint8_t'} } > + > + // Conditional expressions. > + > + 0 ? sve_sc1 : sve_sc1; > + 0 ? sve_sc1 : sve_sh1; // { dg-error {different types 'svint8_t' and 'svint16_t'} } > + 0 ? sve_sc1 : 0; // { dg-error {different types 'svint8_t' and 'int'} } > + 0 ? 0 : sve_sc1; // { dg-error {different types 'int' and 'svint8_t'} } > + 0 ? sve_sc1 : sve_sc1; > + 0 ? sve_sc_ptr : sve_sc_ptr; > + 0 ? sve_sc_ptr : gnu_sc_ptr; > + 0 ? gnu_sc_ptr : sve_sc_ptr; > + > + // Function arguments. > + > + ext_consume_sve_sc (sve_sc1); > + ext_consume_sve_sc (sve_sh1); // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } > + ext_consume_const_int_ref (sve_sc1); // { dg-error {invalid initialization of reference of type 'const int&' from expression of type 'svint8_t'} } > + ext_consume_varargs (sve_sc1); // { dg-error {cannot convert 'svint8_t' to 'int'} } > + 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 {cannot convert 'svint8_t' to 'svint16_t' in assignment} } > + > + // Auto > + > +#if __cplusplus >= 201103L > + auto auto_sve_sc1 = sve_sc1; > + auto auto_sve_sc1_return = ext_produce_sve_sc (); > +#endif > + > + // Varargs processing. > + > + __builtin_va_list valist; > + __builtin_va_arg (valist, svint8_t); > + > + // Other built-ins > + > + __builtin_launder (sve_sc1); // { dg-error {non-pointer argument to '__builtin_launder'} } > + __builtin_memcpy (&sve_sc1, &sve_sc2, 2); > + > + // Lambdas > + > +#if __cplusplus >= 201103L > + [sve_sc1] () {}; // { dg-error {capture by copy of SVE type 'svint8_t'} "" { target c++11 } } > + [=] () { &sve_sc1; }; // { dg-error {capture by copy of SVE type 'svint8_t'} "" { target c++11 } } > + [&sve_sc1] () { sve_sc1 = sve_sc2; }; // { dg-error {'sve_sc2' is not captured} "" { target c++11 } } > + [&sve_sc1, &sve_sc2] () { sve_sc1 = sve_sc2; }; > + [&] () { sve_sc1 = sve_sc2; }; > + [] () { return ext_produce_sve_sc (); } (); > +#endif > + > + // Exceptions > + > + throw svint8_t (); // { dg-error {cannot throw or catch SVE type 'svint8_t'} } > + try {} catch (svint8_t x) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} } > + try {} catch (svint8_t &x) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} } > + try {} catch (svint8_t *x) {} > +#if __cplusplus < 201103L > + thrower2 (); > +#endif > + > + // Use in traits. Doesn't use static_assert so that tests work with > + // earlier -std=s. > + > + { typedef int f[__has_nothrow_assign (svint8_t) ? 1 : -1]; } > + { typedef int f[__has_trivial_assign (svint8_t) ? 1 : -1]; } > + { typedef int f[__has_nothrow_constructor (svint8_t) ? 1 : -1]; } > + { typedef int f[__has_trivial_constructor (svint8_t) ? 1 : -1]; } > + { typedef int f[__has_nothrow_copy (svint8_t) ? 1 : -1]; } > + { typedef int f[__has_trivial_copy (svint8_t) ? 1 : -1]; } > + { typedef int f[__has_trivial_destructor (svint8_t) ? 1 : -1]; } > + { typedef int f[__has_unique_object_representations (svint8_t) ? 1 : -1]; } > + { typedef int f[!__has_virtual_destructor (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_abstract (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_aggregate (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_base_of (svint8_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_base_of (svint8_t, svint16_t) ? 1 : -1]; } > + { typedef int f[!__is_class (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_empty (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_enum (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_final (svint8_t) ? 1 : -1]; } > + { typedef int f[__is_pod (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_polymorphic (svint8_t) ? 1 : -1]; } > + { typedef int f[__is_same_as (svint8_t, svint8_t) ? 1 : -1]; } > + { typedef int f[__is_same_as (svint8_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[__is_same_as (int8x32_t, svint8_t) ? 1 : -1]; } > + { typedef int f[__is_same_as (svint8_t *, svint8_t *) ? 1 : -1]; } > + { typedef int f[__is_same_as (svint8_t *, int8x32_t *) ? 1 : -1]; } > + { typedef int f[__is_same_as (int8x32_t *, svint8_t *) ? 1 : -1]; } > + { typedef int f[!__is_same_as (svint8_t, int) ? 1 : -1]; } > + { typedef int f[!__is_same_as (svint8_t, svint16_t) ? 1 : -1]; } > + { typedef int f[__is_trivial (svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_union (svint8_t) ? 1 : -1]; } > + { typedef int f[__is_trivially_copyable (svint8_t) ? 1 : -1]; } > + /* The intention is that svint8_t should behave like int8x32_t here. If the behavior > + for int8x32_t changes then the behavior for svint8_t should change in the same > + way. */ > + { typedef int f[!__is_trivially_assignable (int8x32_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[!__is_trivially_assignable (svint8_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_trivially_assignable (svint8_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[!__is_trivially_assignable (int8x32_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_trivially_assignable (svint8_t, int) ? 1 : -1]; } > + { typedef int f[!__is_trivially_assignable (svint8_t, svint16_t) ? 1 : -1]; } > + { typedef int f[!__is_assignable (int8x32_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[!__is_assignable (svint8_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_assignable (svint8_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[!__is_assignable (int8x32_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_assignable (svint8_t, int) ? 1 : -1]; } > + { typedef int f[!__is_assignable (svint8_t, svint16_t) ? 1 : -1]; } > + { typedef int f[__is_trivially_constructible (svint8_t) ? 1 : -1]; } > + { typedef int f[__is_trivially_constructible (int8x32_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[__is_trivially_constructible (svint8_t, svint8_t) ? 1 : -1]; } > + { typedef int f[__is_trivially_constructible (svint8_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[__is_trivially_constructible (int8x32_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_trivially_constructible (svint8_t, int) ? 1 : -1]; } > + { typedef int f[!__is_trivially_constructible (svint8_t, svint16_t) ? 1 : -1]; } > + { typedef int f[__is_constructible (svint8_t) ? 1 : -1]; } > + { typedef int f[__is_constructible (int8x32_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[__is_constructible (svint8_t, svint8_t) ? 1 : -1]; } > + { typedef int f[__is_constructible (svint8_t, int8x32_t) ? 1 : -1]; } > + { typedef int f[__is_constructible (int8x32_t, svint8_t) ? 1 : -1]; } > + { typedef int f[!__is_constructible (svint8_t, int) ? 1 : -1]; } > + { typedef int f[!__is_constructible (svint8_t, svint16_t) ? 1 : -1]; } > +} > + > +// Function parameters in definitions. > + > +void > +unnamed_st1 (svint8_t) > +{ > +} > + > +void > +named_st1 (svint8_t param1) > +{ > + svint8_t sve_sc1 = param1; > +} > + > +// Function return values in definitions. > + > +svint8_t > +ret_st1 (svint8_t param) > +{ > + return param; > +} > + > +svint8_t > +bad_ret_st1 (svint16_t param) > +{ > + return param; // { dg-error {cannot convert 'svint16_t' to 'svint8_t' in return} } > +} > + > +#if __cplusplus >= 201103L > +template<typename T> > +void > +const_to_sve_sc (T i) > +{ > + constexpr svint8_t a = (svint8_t) i; > +} > +#endif > + > +template<typename T> > +int > +get_x (T *a) > +{ > + return a->a; // { dg-error {request for member 'a' in '\* a', which is of non-class type} } > +} > +template int get_x<svint8_t>(svint8_t *); > + > +#if __cplusplus < 201103L > +void thrower3 () throw (svint8_t) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } > +#endif > + > +// Using "auto" as a return type. > + > +#if __cplusplus >= 201402L > +auto auto_ret_sve_sc (svint8_t *ptr) { return *ptr; } > +const auto &auto_ret_const_sve_sc_ref (svint8_t *ptr) { return *ptr; } > +auto &auto_ret_sve_sc_ref (svint8_t *ptr) { return *ptr; } > +auto &&auto_ret_sve_sc_rvalue_ref (svint8_t *ptr) { return *ptr; } > +#endif >
Index: gcc/target.h =================================================================== --- gcc/target.h 2019-12-04 10:58:40.000000000 +0000 +++ gcc/target.h 2019-12-04 10:59:10.223988432 +0000 @@ -249,7 +249,19 @@ enum type_context_kind { /* 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 + TCTX_POINTER_ARITH, + + /* Dynamically allocating objects of type T. */ + TCTX_ALLOCATION, + + /* Dynamically deallocating objects of type T. */ + TCTX_DEALLOCATION, + + /* Throwing or catching an object of type T. */ + TCTX_EXCEPTIONS, + + /* Capturing objects of type T by value in a closure. */ + TCTX_CAPTURE_BY_COPY }; extern bool verify_type_context (location_t, type_context_kind, const_tree, Index: gcc/config/aarch64/aarch64-sve-builtins.cc =================================================================== --- gcc/config/aarch64/aarch64-sve-builtins.cc 2019-12-04 10:58:40.000000000 +0000 +++ gcc/config/aarch64/aarch64-sve-builtins.cc 2019-12-04 10:59:10.211988515 +0000 @@ -3352,6 +3352,26 @@ verify_type_context (location_t loc, typ if (!silent_p) error_at (loc, "array elements cannot have SVE type %qT", type); return false; + + case TCTX_ALLOCATION: + if (!silent_p) + error_at (loc, "cannot allocate objects with SVE type %qT", type); + return false; + + case TCTX_DEALLOCATION: + if (!silent_p) + error_at (loc, "cannot delete objects with SVE type %qT", type); + return false; + + case TCTX_EXCEPTIONS: + if (!silent_p) + error_at (loc, "cannot throw or catch SVE type %qT", type); + return false; + + case TCTX_CAPTURE_BY_COPY: + if (!silent_p) + error_at (loc, "capture by copy of SVE type %qT", type); + return false; } gcc_unreachable (); } Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c 2019-12-04 10:58:40.000000000 +0000 +++ gcc/cp/decl.c 2019-12-04 10:59:10.215988487 +0000 @@ -5470,6 +5470,13 @@ start_decl_1 (tree decl, bool initialize cp_apply_type_quals_to_decl (cp_type_quals (type), decl); } + if (is_global_var (decl)) + { + type_context_kind context = (DECL_THREAD_LOCAL_P (decl) + ? TCTX_THREAD_STORAGE + : TCTX_STATIC_STORAGE); + verify_type_context (input_location, context, TREE_TYPE (decl)); + } if (initialized) /* Is it valid for this decl to have an initializer at all? */ { @@ -6527,6 +6534,12 @@ check_array_initializer (tree decl, tree error ("elements of array %q#T have incomplete type", type); return true; } + + location_t loc = (decl && DECL_P (decl) + ? DECL_SOURCE_LOCATION (decl) : input_location); + if (!verify_type_context (loc, TCTX_ARRAY_ELEMENT, element_type)) + return true; + /* A compound literal can't have variable size. */ if (init && !decl && ((COMPLETE_TYPE_P (type) && !TREE_CONSTANT (TYPE_SIZE (type))) @@ -7473,6 +7486,8 @@ cp_finish_decl (tree decl, tree init, bo if (VAR_P (decl) && DECL_CLASS_SCOPE_P (decl) + && verify_type_context (DECL_SOURCE_LOCATION (decl), + TCTX_STATIC_STORAGE, type) && DECL_INITIALIZED_IN_CLASS_P (decl)) check_static_variable_definition (decl, type); @@ -10541,6 +10556,10 @@ create_array_type_for_decl (tree name, t break; } + if (!verify_type_context (name ? loc : input_location, + TCTX_ARRAY_ELEMENT, type)) + return error_mark_node; + /* [dcl.array] The constant expressions that specify the bounds of the arrays @@ -13245,6 +13264,14 @@ grokdeclarator (const cp_declarator *dec decl = NULL_TREE; } } + else if (!verify_type_context (input_location, + staticp + ? TCTX_STATIC_STORAGE + : TCTX_FIELD, type)) + { + type = error_mark_node; + decl = NULL_TREE; + } else { if (friendp) Index: gcc/cp/except.c =================================================================== --- gcc/cp/except.c 2019-12-04 10:58:40.000000000 +0000 +++ gcc/cp/except.c 2019-12-04 10:59:10.215988487 +0000 @@ -29,6 +29,7 @@ the Free Software Foundation; either ver #include "trans-mem.h" #include "attribs.h" #include "tree-iterator.h" +#include "target.h" static void push_eh_cleanup (tree); static tree prepare_eh_type (tree); @@ -927,6 +928,14 @@ is_admissible_throw_operand_or_catch_par if (!complete_ptr_ref_or_void_ptr_p (type, expr)) return false; + else if (!verify_type_context (input_location, TCTX_EXCEPTIONS, type)) + return false; + + else if (TYPE_REF_P (type) + && !verify_type_context (input_location, TCTX_EXCEPTIONS, + TREE_TYPE (type))) + return false; + /* 10.4/3 An abstract class shall not be used as a parameter type, as a function return type or as type of an explicit conversion. */ Index: gcc/cp/typeck2.c =================================================================== --- gcc/cp/typeck2.c 2019-12-04 10:58:40.000000000 +0000 +++ gcc/cp/typeck2.c 2019-12-04 10:59:10.223988432 +0000 @@ -33,6 +33,7 @@ the Free Software Foundation; either ver #include "varasm.h" #include "intl.h" #include "gcc-rich-location.h" +#include "target.h" static tree process_init_constructor (tree type, tree init, int nested, int flags, @@ -2400,6 +2401,9 @@ add_exception_specifier (tree list, tree ok = true; else if (processing_template_decl) ok = true; + else if (!verify_type_context (input_location, TCTX_EXCEPTIONS, core, + !(complain & tf_error))) + return error_mark_node; else { ok = true; Index: gcc/cp/init.c =================================================================== --- gcc/cp/init.c 2019-12-04 10:58:40.000000000 +0000 +++ gcc/cp/init.c 2019-12-04 10:59:10.215988487 +0000 @@ -3058,6 +3058,10 @@ build_new_1 (vec<tree, va_gc> **placemen complain); } + if (!verify_type_context (input_location, TCTX_ALLOCATION, elt_type, + !(complain & tf_error))) + return error_mark_node; + if (variably_modified_type_p (elt_type, NULL_TREE) && (complain & tf_error)) { error ("variably modified type not allowed in new-expression"); @@ -3942,6 +3946,10 @@ build_vec_delete_1 (tree base, tree maxi if (base == error_mark_node || maxindex == error_mark_node) return error_mark_node; + if (!verify_type_context (input_location, TCTX_DEALLOCATION, type, + !(complain & tf_error))) + return error_mark_node; + if (!COMPLETE_TYPE_P (type)) { if (complain & tf_warning) @@ -4827,6 +4835,11 @@ build_delete (tree otype, tree addr, spe if (!VOID_TYPE_P (type)) { complete_type (type); + if (deleting + && !verify_type_context (input_location, TCTX_DEALLOCATION, type, + !(complain & tf_error))) + return error_mark_node; + if (!COMPLETE_TYPE_P (type)) { if (complain & tf_warning) Index: gcc/cp/lambda.c =================================================================== --- gcc/cp/lambda.c 2019-12-04 10:58:40.000000000 +0000 +++ gcc/cp/lambda.c 2019-12-04 10:59:10.215988487 +0000 @@ -30,6 +30,7 @@ #include "tree-iterator.h" #include "toplev.h" #include "gimplify.h" +#include "target.h" /* Constructor for a lambda expression. */ @@ -579,6 +580,9 @@ add_capture (tree lambda, tree id, tree cxx_incomplete_type_inform (type); return error_mark_node; } + else if (!verify_type_context (input_location, + TCTX_CAPTURE_BY_COPY, type)) + return error_mark_node; } } Index: gcc/cp/pt.c =================================================================== --- gcc/cp/pt.c 2019-12-04 10:58:40.000000000 +0000 +++ gcc/cp/pt.c 2019-12-04 10:59:10.223988432 +0000 @@ -42,6 +42,7 @@ the Free Software Foundation; either ver #include "gimplify.h" #include "gcc-rich-location.h" #include "selftest.h" +#include "target.h" /* The type of functions taking a tree, and some additional data, and returning an int. */ @@ -11815,6 +11816,9 @@ instantiate_class_template_1 (tree type) error ("flexible array member %qD in union", r); TREE_TYPE (r) = error_mark_node; } + else if (!verify_type_context (input_location, + TCTX_FIELD, rtype)) + TREE_TYPE (r) = error_mark_node; } /* If it is a TYPE_DECL for a class-scoped ENUMERAL_TYPE, Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c 2019-12-04 10:58:40.000000000 +0000 +++ gcc/cp/typeck.c 2019-12-04 10:59:10.223988432 +0000 @@ -1824,7 +1824,14 @@ cxx_alignof_expr (tree e, tsubst_flags_t e = mark_type_use (e); - if (VAR_P (e)) + if (!verify_type_context (input_location, TCTX_ALIGNOF, TREE_TYPE (e), + !(complain & tf_error))) + { + if (!(complain & tf_error)) + return error_mark_node; + t = size_one_node; + } + else if (VAR_P (e)) t = size_int (DECL_ALIGN_UNIT (e)); else if (bitfield_p (e)) { @@ -5778,6 +5785,13 @@ pointer_diff (location_t loc, tree op0, else return error_mark_node; } + else if (!verify_type_context (loc, TCTX_POINTER_ARITH, + TREE_TYPE (TREE_TYPE (op0)), + !(complain & tf_error)) + || !verify_type_context (loc, TCTX_POINTER_ARITH, + TREE_TYPE (TREE_TYPE (op1)), + !(complain & tf_error))) + return error_mark_node; /* Determine integer type result of the subtraction. This will usually be the same as the result type (ptrdiff_t), but may need to be a wider @@ -6572,6 +6586,10 @@ cp_build_unary_op (enum tree_code code, else return error_mark_node; } + else if (!verify_type_context (location, TCTX_POINTER_ARITH, + TREE_TYPE (argtype), + !(complain & tf_error))) + return error_mark_node; inc = cxx_sizeof_nowarn (TREE_TYPE (argtype)); } Index: gcc/testsuite/g++.dg/ext/sve-sizeless-1.C =================================================================== --- /dev/null 2019-09-17 11:41:18.176664108 +0100 +++ gcc/testsuite/g++.dg/ext/sve-sizeless-1.C 2019-12-04 10:59:10.223988432 +0000 @@ -0,0 +1,418 @@ +// { dg-do compile { target aarch64*-*-* } } +// { dg-options "-Wclass-memaccess" } + +typedef __SIZE_TYPE__ size_t; +inline void *operator new (size_t, void *__p) throw() { return __p; } + +#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} } + +// 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 member variables. + +struct struct1 { + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } +}; + +union union1 { + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } +}; + +#if __cplusplus >= 201103L +struct static_sve_sc { + static svint8_t sve_sc1 = {}; // { dg-error {SVE type 'svint8_t' does not have a fixed size} "" { target c++11 } } +}; +#endif + +// Sizeless member variables in templated structures. + +template<typename T> +struct templated_struct1 { + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } +}; + +template<typename T> +struct templated_struct2 { + T a; // { dg-error {member variables cannot have SVE type '(svint8_t|__SVInt8_t)'} } +}; + +template class templated_struct2<svint8_t>; + +template<typename T> +struct templated_struct3 { + T &a; +}; + +template class templated_struct3<svint8_t>; + +#if __cplusplus >= 201103L +template<typename T> +struct templated_struct4 { + static T a; // { dg-error {SVE type '(svint8_t|__SVInt8_t)' does not have a fixed size} "" { target c++11 } } + static T b = {}; // { dg-error {SVE type '(svint8_t|__SVInt8_t)' does not have a fixed size} "" { target c++11 } } +}; + +template class templated_struct4<svint8_t>; +#endif + +template<typename T> struct templated_struct5 : T {}; // { dg-error {base type '[^']*' fails to be a struct or class type} } +template class templated_struct5<svint8_t>; + +#if __cplusplus >= 201103L +template<int N> using typedef_sizeless1 = svint8_t; +template<int N> using typedef_sizeless1 = svint8_t; // { dg-error {redefinition of 'template<int N> using typedef_sizeless1 = svint8_t'} "" { target c++11 } } +template<typename T> using array = T[2]; +#endif + +// Pointers to sizeless types. + +svint8_t *global_sve_sc_ptr; + +// Sizeless arguments and return values. + +void ext_consume_sve_sc (svint8_t); +void ext_consume_const_int_ref (const int &); +void ext_consume_varargs (int, ...); +svint8_t ext_produce_sve_sc (); + +// Sizeless types in throw specifications. + +#if __cplusplus < 201103L +void thrower1 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +void thrower2 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +void thrower3 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +#endif + +// Main tests for statements and expressions. + +void +statements (int n) +{ + // Local declarations. + + svint8_t sve_sc1, sve_sc2; + volatile svint8_t volatile_sve_sc1; + int8x32_t gnu_sc1; + svint16_t sve_sh1; + + // 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} } + +#if __cplusplus >= 201103L + array<svint8_t> foo = {}; // { dg-error {array elements cannot have SVE type '(svint8_t|__SVInt8_t)'} "" { target c++11 } } +#endif + + // Initialization. + + int init_int1 = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } + int init_int2 = { sve_sc1 }; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } + + svint8_t init_sve_sc1 (sve_sc1); + svint8_t init_sve_sc2 (sve_sh1); // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + svint8_t init_sve_sc3 = sve_sc1; + svint8_t init_sve_sc4 = sve_sh1; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + svint8_t init_sve_sc5 = {}; + svint8_t init_sve_sc6 = { sve_sc1 }; + svint8_t init_sve_sc7 = { sve_sh1 }; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + + // Constructor calls. + + (0, svint8_t ()); + + // Lvalue reference binding + + svint8_t &lvalue_ref_sve_sc1 = sve_sc1; + svint8_t &lvalue_ref_sve_sc2 = ext_produce_sve_sc (); // { dg-error {cannot bind non-const lvalue reference of type 'svint8_t&' to an rvalue of type 'svint8_t'} } + svint8_t &lvalue_ref_sve_sc3 = sve_sh1; // { dg-error {invalid initialization of reference of type 'svint8_t&' from expression of type 'svint16_t'} } + + const svint8_t &const_lvalue_ref_sve_sc1 = sve_sc1; + const svint8_t &const_lvalue_ref_sve_sc2 = ext_produce_sve_sc (); + const svint8_t &const_lvalue_ref_sve_sc3 = sve_sh1; // { dg-error {invalid initialization of reference of type 'const svint8_t&' from expression of type 'svint16_t'} } + + // Compound literals. + + (int) { sve_sc1 }; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } + + // 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'} } + + // Assignment. + + n = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int' in assignment} } + + sve_sc1 = 0; // { dg-error {cannot convert 'int' to 'svint8_t' in assignment} } + sve_sc1 = sve_sc1; + sve_sc1 = gnu_sc1; // { dg-error {cannot convert 'int8x32_t'[^\n]* to 'svint8_t' in assignment} } + gnu_sc1 = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int8x32_t'} } + sve_sc1 = sve_sh1; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + + // Casting. + + (void) sve_sc1; + (void) volatile_sve_sc1; + (void) *&volatile_sve_sc1; + + // Addressing and dereferencing. + + svint8_t *sve_sc_ptr = &sve_sc1; + int8x32_t *gnu_sc_ptr = &gnu_sc1; + sve_sc_ptr = (svint16_t *) 0; // { dg-error {cannot convert 'svint16_t\*' to 'svint8_t\*' in assignment} } + + // Pointer assignment. + + gnu_sc_ptr = sve_sc_ptr; // { dg-error {cannot convert 'svint8_t\*' to 'int8x32_t\*'} } + sve_sc_ptr = gnu_sc_ptr; // { dg-error {cannot convert 'int8x32_t\*'[^\n]* to 'svint8_t\*'} } + + // 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 of types 'int8x32_t\*'[^\n]* and 'svint8_t\*' to binary 'operator-'} } + sve_sc_ptr - gnu_sc_ptr; // { dg-error {invalid operands of types 'svint8_t\*' and 'int8x32_t\*'[^\n]* to binary 'operator-'} } + 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-error {comparison between distinct pointer types [^\n]*lacks a cast} } + gnu_sc_ptr != sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + gnu_sc_ptr < sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + gnu_sc_ptr <= sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + gnu_sc_ptr > sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + gnu_sc_ptr >= sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + sve_sc_ptr == gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + sve_sc_ptr != gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + sve_sc_ptr < gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + sve_sc_ptr <= gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + sve_sc_ptr > gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + sve_sc_ptr >= gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} } + + // New and delete. + + new svint8_t; // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + new svint8_t (); // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + + new (global_sve_sc_ptr) svint8_t; // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + new (global_sve_sc_ptr) svint8_t (); // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + + sve_sc1.~svint8_t(); // { dg-error {expected class-name before '\(' token} } + delete sve_sc_ptr; // { dg-error {cannot delete objects with SVE type '(svint8_t|__SVInt8_t)'} } + delete[] sve_sc_ptr; // { dg-error {cannot delete objects with SVE type 'svint8_t'} } + + // Conditional expressions. + + 0 ? sve_sc1 : sve_sc1; + 0 ? sve_sc1 : sve_sh1; // { dg-error {different types 'svint8_t' and 'svint16_t'} } + 0 ? sve_sc1 : 0; // { dg-error {different types 'svint8_t' and 'int'} } + 0 ? 0 : sve_sc1; // { dg-error {different types 'int' and 'svint8_t'} } + 0 ? sve_sc1 : sve_sc1; + 0 ? sve_sc_ptr : sve_sc_ptr; + 0 ? sve_sc_ptr : gnu_sc_ptr; // { dg-error {conditional expression between distinct pointer types [^\n]*lacks a cast} } + 0 ? gnu_sc_ptr : sve_sc_ptr; // { dg-error {conditional expression between distinct pointer types [^\n]*lacks a cast} } + + // Function arguments. + + ext_consume_sve_sc (sve_sc1); + ext_consume_sve_sc (sve_sh1); // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + ext_consume_const_int_ref (sve_sc1); // { dg-error {invalid initialization of reference of type 'const int&' from expression of type 'svint8_t'} } + ext_consume_varargs (sve_sc1); // { dg-error {cannot convert 'svint8_t' to 'int'} } + 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 {cannot convert 'svint8_t' to 'svint16_t' in assignment} } + + // Auto + +#if __cplusplus >= 201103L + auto auto_sve_sc1 = sve_sc1; + auto auto_sve_sc1_return = ext_produce_sve_sc (); +#endif + + // Varargs processing. + + __builtin_va_list valist; + __builtin_va_arg (valist, svint8_t); + + // Other built-ins + + __builtin_launder (sve_sc1); // { dg-error {non-pointer argument to '__builtin_launder'} } + __builtin_memcpy (&sve_sc1, &sve_sc2, 2); + + // Lambdas + +#if __cplusplus >= 201103L + [sve_sc1] () {}; // { dg-error {capture by copy of SVE type 'svint8_t'} "" { target c++11 } } + [=] () { &sve_sc1; }; // { dg-error {capture by copy of SVE type 'svint8_t'} "" { target c++11 } } + [&sve_sc1] () { sve_sc1 = sve_sc2; }; // { dg-error {'sve_sc2' is not captured} "" { target c++11 } } + [&sve_sc1, &sve_sc2] () { sve_sc1 = sve_sc2; }; + [&] () { sve_sc1 = sve_sc2; }; + [] () { return ext_produce_sve_sc (); } (); +#endif + + // Exceptions + + throw svint8_t (); // { dg-error {cannot throw or catch SVE type 'svint8_t'} } + try {} catch (svint8_t x) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} } + try {} catch (svint8_t &x) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} } + try {} catch (svint8_t *x) {} +#if __cplusplus < 201103L + thrower2 (); +#endif + + // Use in traits. Doesn't use static_assert so that tests work with + // earlier -std=s. + + { typedef int f[__has_nothrow_assign (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_assign (svint8_t) ? 1 : -1]; } + { typedef int f[__has_nothrow_constructor (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_constructor (svint8_t) ? 1 : -1]; } + { typedef int f[__has_nothrow_copy (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_copy (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_destructor (svint8_t) ? 1 : -1]; } + { typedef int f[__has_unique_object_representations (svint8_t) ? 1 : -1]; } + { typedef int f[!__has_virtual_destructor (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_abstract (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_aggregate (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_base_of (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_base_of (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[!__is_class (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_empty (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_enum (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_final (svint8_t) ? 1 : -1]; } + { typedef int f[__is_pod (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_polymorphic (svint8_t) ? 1 : -1]; } + { typedef int f[__is_same_as (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_same_as (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_same_as (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[__is_same_as (svint8_t *, svint8_t *) ? 1 : -1]; } + { typedef int f[!__is_same_as (svint8_t *, int8x32_t *) ? 1 : -1]; } + { typedef int f[!__is_same_as (int8x32_t *, svint8_t *) ? 1 : -1]; } + { typedef int f[!__is_same_as (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_same_as (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[__is_trivial (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_union (svint8_t) ? 1 : -1]; } + { typedef int f[__is_trivially_copyable (svint8_t) ? 1 : -1]; } + /* The intention is that svint8_t should behave like int8x32_t here. If the behavior + for int8x32_t changes then the behavior for svint8_t should change in the same + way. */ + { typedef int f[!__is_trivially_assignable (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (svint8_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_constructible (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_constructible (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_constructible (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_trivially_constructible (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[__is_constructible (svint8_t) ? 1 : -1]; } + { typedef int f[__is_constructible (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[__is_constructible (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_constructible (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_constructible (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_constructible (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_constructible (svint8_t, svint16_t) ? 1 : -1]; } +} + +// Function parameters in definitions. + +void +unnamed_st1 (svint8_t) +{ +} + +void +named_st1 (svint8_t param1) +{ + svint8_t sve_sc1 = param1; +} + +// Function return values in definitions. + +svint8_t +ret_st1 (svint8_t param) +{ + return param; +} + +svint8_t +bad_ret_st1 (svint16_t param) +{ + return param; // { dg-error {cannot convert 'svint16_t' to 'svint8_t' in return} } +} + +#if __cplusplus >= 201103L +template<typename T> +void +const_to_sve_sc (T i) +{ + constexpr svint8_t a = (svint8_t) i; +} +#endif + +template<typename T> +int +get_x (T *a) +{ + return a->a; // { dg-error {request for member 'a' in '\* a', which is of non-class type} } +} +template int get_x<svint8_t>(svint8_t *); + +#if __cplusplus < 201103L +void thrower3 () throw (svint8_t) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +#endif + +// Using "auto" as a return type. + +#if __cplusplus >= 201402L +auto auto_ret_sve_sc (svint8_t *ptr) { return *ptr; } +const auto &auto_ret_const_sve_sc_ref (svint8_t *ptr) { return *ptr; } +auto &auto_ret_sve_sc_ref (svint8_t *ptr) { return *ptr; } +auto &&auto_ret_sve_sc_rvalue_ref (svint8_t *ptr) { return *ptr; } +#endif Index: gcc/testsuite/g++.dg/ext/sve-sizeless-2.C =================================================================== --- /dev/null 2019-09-17 11:41:18.176664108 +0100 +++ gcc/testsuite/g++.dg/ext/sve-sizeless-2.C 2019-12-04 10:59:10.223988432 +0000 @@ -0,0 +1,418 @@ +// { dg-do compile { target aarch64*-*-* } } +// { dg-options "-Wclass-memaccess -msve-vector-bits=256" } + +typedef __SIZE_TYPE__ size_t; +inline void *operator new (size_t, void *__p) throw() { return __p; } + +#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} } + +// 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 member variables. + +struct struct1 { + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } +}; + +union union1 { + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } +}; + +#if __cplusplus >= 201103L +struct static_sve_sc { + static svint8_t sve_sc1 = {}; // { dg-error {SVE type 'svint8_t' does not have a fixed size} "" { target c++11 } } +}; +#endif + +// Sizeless member variables in templated structures. + +template<typename T> +struct templated_struct1 { + svint8_t a; // { dg-error {member variables cannot have SVE type 'svint8_t'} } +}; + +template<typename T> +struct templated_struct2 { + T a; // { dg-error {member variables cannot have SVE type '(svint8_t|__SVInt8_t)'} } +}; + +template class templated_struct2<svint8_t>; + +template<typename T> +struct templated_struct3 { + T &a; +}; + +template class templated_struct3<svint8_t>; + +#if __cplusplus >= 201103L +template<typename T> +struct templated_struct4 { + static T a; // { dg-error {SVE type '(svint8_t|__SVInt8_t)' does not have a fixed size} "" { target c++11 } } + static T b = {}; // { dg-error {SVE type '(svint8_t|__SVInt8_t)' does not have a fixed size} "" { target c++11 } } +}; + +template class templated_struct4<svint8_t>; +#endif + +template<typename T> struct templated_struct5 : T {}; // { dg-error {base type '[^']*' fails to be a struct or class type} } +template class templated_struct5<svint8_t>; + +#if __cplusplus >= 201103L +template<int N> using typedef_sizeless1 = svint8_t; +template<int N> using typedef_sizeless1 = svint8_t; // { dg-error {redefinition of 'template<int N> using typedef_sizeless1 = svint8_t'} "" { target c++11 } } +template<typename T> using array = T[2]; +#endif + +// Pointers to sizeless types. + +svint8_t *global_sve_sc_ptr; + +// Sizeless arguments and return values. + +void ext_consume_sve_sc (svint8_t); +void ext_consume_const_int_ref (const int &); +void ext_consume_varargs (int, ...); +svint8_t ext_produce_sve_sc (); + +// Sizeless types in throw specifications. + +#if __cplusplus < 201103L +void thrower1 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +void thrower2 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +void thrower3 () throw (svint8_t); // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +#endif + +// Main tests for statements and expressions. + +void +statements (int n) +{ + // Local declarations. + + svint8_t sve_sc1, sve_sc2; + volatile svint8_t volatile_sve_sc1; + int8x32_t gnu_sc1; + svint16_t sve_sh1; + + // 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} } + +#if __cplusplus >= 201103L + array<svint8_t> foo = {}; // { dg-error {array elements cannot have SVE type '(svint8_t|__SVInt8_t)'} "" { target c++11 } } +#endif + + // Initialization. + + int init_int1 = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } + int init_int2 = { sve_sc1 }; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } + + svint8_t init_sve_sc1 (sve_sc1); + svint8_t init_sve_sc2 (sve_sh1); // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + svint8_t init_sve_sc3 = sve_sc1; + svint8_t init_sve_sc4 = sve_sh1; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + svint8_t init_sve_sc5 = {}; + svint8_t init_sve_sc6 = { sve_sc1 }; + svint8_t init_sve_sc7 = { sve_sh1 }; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + + // Constructor calls. + + (0, svint8_t ()); + + // Lvalue reference binding + + svint8_t &lvalue_ref_sve_sc1 = sve_sc1; + svint8_t &lvalue_ref_sve_sc2 = ext_produce_sve_sc (); // { dg-error {cannot bind non-const lvalue reference of type 'svint8_t&' to an rvalue of type 'svint8_t'} } + svint8_t &lvalue_ref_sve_sc3 = sve_sh1; // { dg-error {invalid initialization of reference of type 'svint8_t&' from expression of type 'svint16_t'} } + + const svint8_t &const_lvalue_ref_sve_sc1 = sve_sc1; + const svint8_t &const_lvalue_ref_sve_sc2 = ext_produce_sve_sc (); + const svint8_t &const_lvalue_ref_sve_sc3 = sve_sh1; // { dg-error {invalid initialization of reference of type 'const svint8_t&' from expression of type 'svint16_t'} } + + // Compound literals. + + (int) { sve_sc1 }; // { dg-error {cannot convert 'svint8_t' to 'int' in initialization} } + + // 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'} } + + // Assignment. + + n = sve_sc1; // { dg-error {cannot convert 'svint8_t' to 'int' in assignment} } + + sve_sc1 = 0; // { dg-error {cannot convert 'int' to 'svint8_t' in assignment} } + sve_sc1 = sve_sc1; + sve_sc1 = gnu_sc1; + gnu_sc1 = sve_sc1; + sve_sc1 = sve_sh1; // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + + // Casting. + + (void) sve_sc1; + (void) volatile_sve_sc1; + (void) *&volatile_sve_sc1; + + // Addressing and dereferencing. + + svint8_t *sve_sc_ptr = &sve_sc1; + int8x32_t *gnu_sc_ptr = &gnu_sc1; + sve_sc_ptr = (svint16_t *) 0; // { dg-error {cannot convert 'svint16_t\*' to 'svint8_t\*' in assignment} } + + // 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; + + // New and delete. + + new svint8_t; // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + new svint8_t (); // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + + new (global_sve_sc_ptr) svint8_t; // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + new (global_sve_sc_ptr) svint8_t (); // { dg-error {cannot allocate objects with SVE type 'svint8_t'} } + + sve_sc1.~svint8_t(); // { dg-error {expected class-name before '\(' token} } + delete sve_sc_ptr; // { dg-error {cannot delete objects with SVE type '(svint8_t|__SVInt8_t)'} } + delete[] sve_sc_ptr; // { dg-error {cannot delete objects with SVE type 'svint8_t'} } + + // Conditional expressions. + + 0 ? sve_sc1 : sve_sc1; + 0 ? sve_sc1 : sve_sh1; // { dg-error {different types 'svint8_t' and 'svint16_t'} } + 0 ? sve_sc1 : 0; // { dg-error {different types 'svint8_t' and 'int'} } + 0 ? 0 : sve_sc1; // { dg-error {different types 'int' and 'svint8_t'} } + 0 ? sve_sc1 : sve_sc1; + 0 ? sve_sc_ptr : sve_sc_ptr; + 0 ? sve_sc_ptr : gnu_sc_ptr; + 0 ? gnu_sc_ptr : sve_sc_ptr; + + // Function arguments. + + ext_consume_sve_sc (sve_sc1); + ext_consume_sve_sc (sve_sh1); // { dg-error {cannot convert 'svint16_t' to 'svint8_t'} } + ext_consume_const_int_ref (sve_sc1); // { dg-error {invalid initialization of reference of type 'const int&' from expression of type 'svint8_t'} } + ext_consume_varargs (sve_sc1); // { dg-error {cannot convert 'svint8_t' to 'int'} } + 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 {cannot convert 'svint8_t' to 'svint16_t' in assignment} } + + // Auto + +#if __cplusplus >= 201103L + auto auto_sve_sc1 = sve_sc1; + auto auto_sve_sc1_return = ext_produce_sve_sc (); +#endif + + // Varargs processing. + + __builtin_va_list valist; + __builtin_va_arg (valist, svint8_t); + + // Other built-ins + + __builtin_launder (sve_sc1); // { dg-error {non-pointer argument to '__builtin_launder'} } + __builtin_memcpy (&sve_sc1, &sve_sc2, 2); + + // Lambdas + +#if __cplusplus >= 201103L + [sve_sc1] () {}; // { dg-error {capture by copy of SVE type 'svint8_t'} "" { target c++11 } } + [=] () { &sve_sc1; }; // { dg-error {capture by copy of SVE type 'svint8_t'} "" { target c++11 } } + [&sve_sc1] () { sve_sc1 = sve_sc2; }; // { dg-error {'sve_sc2' is not captured} "" { target c++11 } } + [&sve_sc1, &sve_sc2] () { sve_sc1 = sve_sc2; }; + [&] () { sve_sc1 = sve_sc2; }; + [] () { return ext_produce_sve_sc (); } (); +#endif + + // Exceptions + + throw svint8_t (); // { dg-error {cannot throw or catch SVE type 'svint8_t'} } + try {} catch (svint8_t x) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} } + try {} catch (svint8_t &x) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} } + try {} catch (svint8_t *x) {} +#if __cplusplus < 201103L + thrower2 (); +#endif + + // Use in traits. Doesn't use static_assert so that tests work with + // earlier -std=s. + + { typedef int f[__has_nothrow_assign (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_assign (svint8_t) ? 1 : -1]; } + { typedef int f[__has_nothrow_constructor (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_constructor (svint8_t) ? 1 : -1]; } + { typedef int f[__has_nothrow_copy (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_copy (svint8_t) ? 1 : -1]; } + { typedef int f[__has_trivial_destructor (svint8_t) ? 1 : -1]; } + { typedef int f[__has_unique_object_representations (svint8_t) ? 1 : -1]; } + { typedef int f[!__has_virtual_destructor (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_abstract (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_aggregate (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_base_of (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_base_of (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[!__is_class (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_empty (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_enum (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_final (svint8_t) ? 1 : -1]; } + { typedef int f[__is_pod (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_polymorphic (svint8_t) ? 1 : -1]; } + { typedef int f[__is_same_as (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[__is_same_as (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[__is_same_as (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[__is_same_as (svint8_t *, svint8_t *) ? 1 : -1]; } + { typedef int f[__is_same_as (svint8_t *, int8x32_t *) ? 1 : -1]; } + { typedef int f[__is_same_as (int8x32_t *, svint8_t *) ? 1 : -1]; } + { typedef int f[!__is_same_as (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_same_as (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[__is_trivial (svint8_t) ? 1 : -1]; } + { typedef int f[!__is_union (svint8_t) ? 1 : -1]; } + { typedef int f[__is_trivially_copyable (svint8_t) ? 1 : -1]; } + /* The intention is that svint8_t should behave like int8x32_t here. If the behavior + for int8x32_t changes then the behavior for svint8_t should change in the same + way. */ + { typedef int f[!__is_trivially_assignable (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_trivially_assignable (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_assignable (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (svint8_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[__is_trivially_constructible (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_trivially_constructible (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_trivially_constructible (svint8_t, svint16_t) ? 1 : -1]; } + { typedef int f[__is_constructible (svint8_t) ? 1 : -1]; } + { typedef int f[__is_constructible (int8x32_t, int8x32_t) ? 1 : -1]; } + { typedef int f[__is_constructible (svint8_t, svint8_t) ? 1 : -1]; } + { typedef int f[__is_constructible (svint8_t, int8x32_t) ? 1 : -1]; } + { typedef int f[__is_constructible (int8x32_t, svint8_t) ? 1 : -1]; } + { typedef int f[!__is_constructible (svint8_t, int) ? 1 : -1]; } + { typedef int f[!__is_constructible (svint8_t, svint16_t) ? 1 : -1]; } +} + +// Function parameters in definitions. + +void +unnamed_st1 (svint8_t) +{ +} + +void +named_st1 (svint8_t param1) +{ + svint8_t sve_sc1 = param1; +} + +// Function return values in definitions. + +svint8_t +ret_st1 (svint8_t param) +{ + return param; +} + +svint8_t +bad_ret_st1 (svint16_t param) +{ + return param; // { dg-error {cannot convert 'svint16_t' to 'svint8_t' in return} } +} + +#if __cplusplus >= 201103L +template<typename T> +void +const_to_sve_sc (T i) +{ + constexpr svint8_t a = (svint8_t) i; +} +#endif + +template<typename T> +int +get_x (T *a) +{ + return a->a; // { dg-error {request for member 'a' in '\* a', which is of non-class type} } +} +template int get_x<svint8_t>(svint8_t *); + +#if __cplusplus < 201103L +void thrower3 () throw (svint8_t) {} // { dg-error {cannot throw or catch SVE type 'svint8_t'} "" { target c++98_only } } +#endif + +// Using "auto" as a return type. + +#if __cplusplus >= 201402L +auto auto_ret_sve_sc (svint8_t *ptr) { return *ptr; } +const auto &auto_ret_const_sve_sc_ref (svint8_t *ptr) { return *ptr; } +auto &auto_ret_sve_sc_ref (svint8_t *ptr) { return *ptr; } +auto &&auto_ret_sve_sc_rvalue_ref (svint8_t *ptr) { return *ptr; } +#endif