aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2019-11-30 18:50:06 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2019-11-30 18:50:06 +0000
commit65ef05d0b7fb429c5760189e638c441dc3da33f4 (patch)
tree0f798da78b2315a23be7f7f79b6a7fa0380a0ecf /gcc/c
parentb74d8dc4cf11da599b5c18d77a5039bc800d6871 (diff)
downloadgcc-65ef05d0b7fb429c5760189e638c441dc3da33f4.zip
gcc-65ef05d0b7fb429c5760189e638c441dc3da33f4.tar.gz
gcc-65ef05d0b7fb429c5760189e638c441dc3da33f4.tar.bz2
[C] Add a target hook that allows targets to verify type usage
This patch adds a new target hook to check whether there are any target-specific reasons why a type cannot be used in a certain source-language context. It works in a similar way to existing hooks like TARGET_INVALID_CONVERSION and TARGET_INVALID_UNARY_OP. The reason for adding the hook is to report invalid uses of SVE types. Throughout a TU, the SVE vector and predicate types represent values that can be stored in an SVE vector or predicate register. At certain points in the TU we might be able to generate code that assumes the registers have a particular size, but often we can't. In some cases we might even make multiple different assumptions in the same TU (e.g. when implementing an ifunc for multiple vector lengths). But SVE types themselves are the same type throughout. The register size assumptions change how we generate code, but they don't change the definition of the types. This means that the types do not have a fixed size at the C level even when -msve-vector-bits=N is in effect. It also means that the size does not work in the same way as for C VLAs, where the abstract machine evaluates the size at a particular point and then carries that size forward to later code. The SVE ACLE deals with this by making it invalid to use C and C++ constructs that depend on the size or layout of SVE types. The spec refers to the types as "sizeless" types and defines their semantics as edits to the standards. See: https://gcc.gnu.org/ml/gcc-patches/2018-10/msg00868.html for a fuller description and: https://gcc.gnu.org/ml/gcc/2019-11/msg00088.html for a recent update on the status. However, since all current sizeless types are target-specific built-in types, there's no real reason for the frontends to handle them directly. They can just hand off the checks to target code instead. It's then possible for the errors to refer to "SVE types" rather than "sizeless types", which is likely to be more meaningful to users. There is a slight overlap between the new tests and the ones for gnu_vector_type_p in r277950, but here the emphasis is on testing sizelessness. 2019-11-30 Richard Sandiford <richard.sandiford@arm.com> gcc/ * target.h (type_context_kind): New enum. (verify_type_context): Declare. * target.def (verify_type_context): New target hook. * doc/tm.texi.in (TARGET_VERIFY_TYPE_CONTEXT): Likewise. * doc/tm.texi: Regenerate. * tree.c (verify_type_context): New function. * config/aarch64/aarch64-protos.h (aarch64_sve::verify_type_context): Declare. * config/aarch64/aarch64-sve-builtins.cc (verify_type_context): New function. * config/aarch64/aarch64.c (aarch64_verify_type_context): Likewise. (TARGET_VERIFY_TYPE_CONTEXT): Define. gcc/c-family/ * c-common.c (pointer_int_sum): Use verify_type_context to check whether the target allows pointer arithmetic for the types involved. (c_sizeof_or_alignof_type, c_alignof_expr): Use verify_type_context to check whether the target allows sizeof and alignof operations for the types involved. gcc/c/ * c-decl.c (start_decl): Allow initialization of variables whose size is a POLY_INT_CST. (finish_decl): Use verify_type_context to check whether the target allows variables with a particular type to have static or thread-local storage duration. Don't raise a second error if such variables do not have a constant size. (grokdeclarator): Use verify_type_context to check whether the target allows fields or array elements to have a particular type. * c-typeck.c (pointer_diff): Use verify_type_context to test whether the target allows pointer difference for the types involved. (build_unary_op): Likewise for pointer increment and decrement. gcc/testsuite/ * gcc.target/aarch64/sve/acle/general-c/sizeless-1.c: New test. * gcc.target/aarch64/sve/acle/general-c/sizeless-2.c: Likewise. From-SVN: r278877
Diffstat (limited to 'gcc/c')
-rw-r--r--gcc/c/ChangeLog14
-rw-r--r--gcc/c/c-decl.c29
-rw-r--r--gcc/c/c-typeck.c8
3 files changed, 49 insertions, 2 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index b69e82d..8fee474 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,17 @@
+2019-11-30 Richard Sandiford <richard.sandiford@arm.com>
+
+ * c-decl.c (start_decl): Allow initialization of variables whose
+ size is a POLY_INT_CST.
+ (finish_decl): Use verify_type_context to check whether the target
+ allows variables with a particular type to have static or thread-local
+ storage duration. Don't raise a second error if such variables do
+ not have a constant size.
+ (grokdeclarator): Use verify_type_context to check whether the
+ target allows fields or array elements to have a particular type.
+ * c-typeck.c (pointer_diff): Use verify_type_context to test whether
+ the target allows pointer difference for the types involved.
+ (build_unary_op): Likewise for pointer increment and decrement.
+
2019-11-29 Joseph Myers <joseph@codesourcery.com>
* c-parser.c (struct c_parser): Add members raw_tokens and
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 292a4cc..fa7dea5 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -5021,7 +5021,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
{
/* A complete type is ok if size is fixed. */
- if (TREE_CODE (TYPE_SIZE (TREE_TYPE (decl))) != INTEGER_CST
+ if (!poly_int_tree_p (TYPE_SIZE (TREE_TYPE (decl)))
|| C_DECL_VARIABLE_SIZE (decl))
{
error ("variable-sized object may not be initialized");
@@ -5304,6 +5304,15 @@ finish_decl (tree decl, location_t init_loc, tree init,
complete_flexible_array_elts (DECL_INITIAL (decl));
+ if (is_global_var (decl))
+ {
+ type_context_kind context = (DECL_THREAD_LOCAL_P (decl)
+ ? TCTX_THREAD_STORAGE
+ : TCTX_STATIC_STORAGE);
+ if (!verify_type_context (input_location, context, TREE_TYPE (decl)))
+ TREE_TYPE (decl) = error_mark_node;
+ }
+
if (DECL_SIZE (decl) == NULL_TREE && TREE_TYPE (decl) != error_mark_node
&& COMPLETE_TYPE_P (TREE_TYPE (decl)))
layout_decl (decl, 0);
@@ -5333,7 +5342,9 @@ finish_decl (tree decl, location_t init_loc, tree init,
&& TREE_STATIC (decl))
incomplete_record_decls.safe_push (decl);
- if (is_global_var (decl) && DECL_SIZE (decl) != NULL_TREE)
+ if (is_global_var (decl)
+ && DECL_SIZE (decl) != NULL_TREE
+ && TREE_TYPE (decl) != error_mark_node)
{
if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST)
constant_expression_warning (DECL_SIZE (decl));
@@ -5653,6 +5664,10 @@ build_compound_literal (location_t loc, tree type, tree init, bool non_const,
return error_mark_node;
}
+ if (TREE_STATIC (decl)
+ && !verify_type_context (loc, TCTX_STATIC_STORAGE, type))
+ return error_mark_node;
+
stmt = build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl);
complit = build1 (COMPOUND_LITERAL_EXPR, type, stmt);
TREE_SIDE_EFFECTS (complit) = 1;
@@ -6370,6 +6385,12 @@ grokdeclarator (const struct c_declarator *declarator,
if (type == error_mark_node)
continue;
+ if (!verify_type_context (loc, TCTX_ARRAY_ELEMENT, type))
+ {
+ type = error_mark_node;
+ continue;
+ }
+
/* If size was specified, set ITYPE to a range-type for
that size. Otherwise, ITYPE remains null. finish_decl
may figure it out from an initial value. */
@@ -7217,6 +7238,10 @@ grokdeclarator (const struct c_declarator *declarator,
if (orig_qual_indirect == 0)
orig_qual_type = NULL_TREE;
}
+ if (type != error_mark_node
+ && !verify_type_context (loc, TCTX_FIELD, type))
+ type = error_mark_node;
+
type = c_build_qualified_type (type, type_quals, orig_qual_type,
orig_qual_indirect);
decl = build_decl (declarator->id_loc,
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 5f74a3b..f9ab1e3 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -3892,6 +3892,7 @@ pointer_diff (location_t loc, tree op0, tree op1, tree *instrument_expr)
addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op0)));
addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op1)));
tree target_type = TREE_TYPE (TREE_TYPE (op0));
+ tree orig_op0 = op0;
tree orig_op1 = op1;
/* If the operands point into different address spaces, we need to
@@ -3962,6 +3963,10 @@ pointer_diff (location_t loc, tree op0, tree op1, tree *instrument_expr)
/* This generates an error if op1 is pointer to incomplete type. */
if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1))))
error_at (loc, "arithmetic on pointer to an incomplete type");
+ else if (verify_type_context (loc, TCTX_POINTER_ARITH,
+ TREE_TYPE (TREE_TYPE (orig_op0))))
+ verify_type_context (loc, TCTX_POINTER_ARITH,
+ TREE_TYPE (TREE_TYPE (orig_op1)));
op1 = c_size_in_bytes (target_type);
@@ -4614,6 +4619,9 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
pedwarn (location, OPT_Wpointer_arith,
"wrong type argument to decrement");
}
+ else
+ verify_type_context (location, TCTX_POINTER_ARITH,
+ TREE_TYPE (argtype));
inc = c_size_in_bytes (TREE_TYPE (argtype));
inc = convert_to_ptrofftype_loc (location, inc);