aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-decl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c/c-decl.cc')
-rw-r--r--gcc/c/c-decl.cc130
1 files changed, 121 insertions, 9 deletions
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index ffa63dc..193e268 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5034,6 +5034,41 @@ set_array_declarator_inner (struct c_declarator *decl,
return decl;
}
+/* Determine whether TYPE is a ISO C99 flexible array memeber type "[]". */
+static bool
+flexible_array_member_type_p (const_tree type)
+{
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && TYPE_SIZE (type) == NULL_TREE
+ && TYPE_DOMAIN (type) != NULL_TREE
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+ return true;
+
+ return false;
+}
+
+/* Determine whether TYPE is a one-element array type "[1]". */
+static bool
+one_element_array_type_p (const_tree type)
+{
+ if (TREE_CODE (type) != ARRAY_TYPE)
+ return false;
+ return integer_zerop (array_type_nelts (type));
+}
+
+/* Determine whether TYPE is a zero-length array type "[0]". */
+static bool
+zero_length_array_type_p (const_tree type)
+{
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ if (tree type_size = TYPE_SIZE_UNIT (type))
+ if ((integer_zerop (type_size))
+ && TYPE_DOMAIN (type) != NULL_TREE
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+ return true;
+ return false;
+}
+
/* INIT is a constructor that forms DECL's initializer. If the final
element initializes a flexible array field, add the size of that
initializer to DECL's size. */
@@ -5048,10 +5083,7 @@ add_flexible_array_elts_to_size (tree decl, tree init)
elt = CONSTRUCTOR_ELTS (init)->last ().value;
type = TREE_TYPE (elt);
- if (TREE_CODE (type) == ARRAY_TYPE
- && TYPE_SIZE (type) == NULL_TREE
- && TYPE_DOMAIN (type) != NULL_TREE
- && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+ if (flexible_array_member_type_p (type))
{
complete_array_type (&type, elt, false);
DECL_SIZE (decl)
@@ -8755,6 +8787,81 @@ finish_incomplete_vars (tree incomplete_vars, bool toplevel)
}
}
+
+/* Determine whether the FIELD_DECL X is a flexible array member according to
+ the following info:
+ A. whether the FIELD_DECL X is the last field of the DECL_CONTEXT;
+ B. whether the FIELD_DECL is an array that is declared as "[]", "[0]",
+ or "[1]";
+ C. flag_strict_flex_arrays;
+ D. the attribute strict_flex_array that is attached to the field
+ if presenting.
+ Return TRUE when it's a flexible array member, FALSE otherwise. */
+
+static bool
+is_flexible_array_member_p (bool is_last_field,
+ tree x)
+{
+ /* If not the last field, return false. */
+ if (!is_last_field)
+ return false;
+
+ /* If not an array field, return false. */
+ if (TREE_CODE (TREE_TYPE (x)) != ARRAY_TYPE)
+ return false;
+
+ bool is_zero_length_array = zero_length_array_type_p (TREE_TYPE (x));
+ bool is_one_element_array = one_element_array_type_p (TREE_TYPE (x));
+ bool is_flexible_array = flexible_array_member_type_p (TREE_TYPE (x));
+
+ unsigned int strict_flex_array_level = flag_strict_flex_arrays;
+
+ tree attr_strict_flex_array = lookup_attribute ("strict_flex_array",
+ DECL_ATTRIBUTES (x));
+ /* If there is a strict_flex_array attribute attached to the field,
+ override the flag_strict_flex_arrays. */
+ if (attr_strict_flex_array)
+ {
+ /* Get the value of the level first from the attribute. */
+ unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
+ gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
+ attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
+ gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
+ attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
+ gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
+ attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
+
+ /* The attribute has higher priority than flag_struct_flex_array. */
+ strict_flex_array_level = attr_strict_flex_array_level;
+ }
+
+ switch (strict_flex_array_level)
+ {
+ case 0:
+ /* Default, all trailing arrays are flexible array members. */
+ return true;
+ case 1:
+ /* Level 1: all "[1]", "[0]", and "[]" are flexible array members. */
+ if (is_one_element_array)
+ return true;
+ /* FALLTHROUGH. */
+ case 2:
+ /* Level 2: all "[0]", and "[]" are flexible array members. */
+ if (is_zero_length_array)
+ return true;
+ /* FALLTHROUGH. */
+ case 3:
+ /* Level 3: Only "[]" are flexible array members. */
+ if (is_flexible_array)
+ return true;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ return false;
+}
+
+
/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
LOC is the location of the RECORD_TYPE or UNION_TYPE's definition.
FIELDLIST is a chain of FIELD_DECL nodes for the fields.
@@ -8816,6 +8923,11 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
bool saw_named_field = false;
for (x = fieldlist; x; x = DECL_CHAIN (x))
{
+ /* Whether this field is the last field of the structure or union.
+ for UNION, any field is the last field of it. */
+ bool is_last_field = (DECL_CHAIN (x) == NULL_TREE)
+ || (TREE_CODE (t) == UNION_TYPE);
+
if (TREE_TYPE (x) == error_mark_node)
continue;
@@ -8854,10 +8966,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
DECL_PACKED (x) = 1;
/* Detect flexible array member in an invalid context. */
- if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
- && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
- && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE
- && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE)
+ if (flexible_array_member_type_p (TREE_TYPE (x)))
{
if (TREE_CODE (t) == UNION_TYPE)
{
@@ -8865,7 +8974,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
"flexible array member in union");
TREE_TYPE (x) = error_mark_node;
}
- else if (DECL_CHAIN (x) != NULL_TREE)
+ else if (!is_last_field)
{
error_at (DECL_SOURCE_LOCATION (x),
"flexible array member not at end of struct");
@@ -8885,6 +8994,9 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic,
"invalid use of structure with flexible array member");
+ /* Set DECL_NOT_FLEXARRAY flag for FIELD_DECL x. */
+ DECL_NOT_FLEXARRAY (x) = !is_flexible_array_member_p (is_last_field, x);
+
if (DECL_NAME (x)
|| RECORD_OR_UNION_TYPE_P (TREE_TYPE (x)))
saw_named_field = true;