diff options
author | Qing Zhao <qing.zhao@oracle.com> | 2022-10-07 14:58:20 +0000 |
---|---|---|
committer | Qing Zhao <qing.zhao@oracle.com> | 2022-10-07 17:44:08 +0000 |
commit | 1879e48f3d8595bc9e7f583bbd12df3c6f5c42dc (patch) | |
tree | 981a0bf7f72cf12425310915f8def6350def1a77 /gcc/c | |
parent | 21e51a55e9714d14a6df0e8e83ae005eb19f0f02 (diff) | |
download | gcc-1879e48f3d8595bc9e7f583bbd12df3c6f5c42dc.zip gcc-1879e48f3d8595bc9e7f583bbd12df3c6f5c42dc.tar.gz gcc-1879e48f3d8595bc9e7f583bbd12df3c6f5c42dc.tar.bz2 |
Add a new option -fstrict-flex-arrays[=n] and new attribute strict_flex_array
Add the following new option -fstrict-flex-arrays[=n] and a corresponding
attribute strict_flex_array to GCC:
'-fstrict-flex-arrays'
Control when to treat the trailing array of a structure as a flexible array
member for the purpose of accessing the elements of such an array.
The positive form is equivalent to '-fstrict-flex-arrays=3', which is the
strictest. A trailing array is treated as a flexible array member only when
it declared as a flexible array member per C99 standard onwards.
The negative form is equivalent to '-fstrict-flex-arrays=0', which is the
least strict. All trailing arrays of structures are treated as flexible
array members.
'-fstrict-flex-arrays=LEVEL'
Control when to treat the trailing array of a structure as a flexible array
member for the purpose of accessing the elements of such an array. The value
of LEVEL controls the level of strictness
The possible values of LEVEL are the same as for the
'strict_flex_array' attribute (*note Variable Attributes::).
You can control this behavior for a specific trailing array field
of a structure by using the variable attribute 'strict_flex_array'
attribute (*note Variable Attributes::).
'strict_flex_array (LEVEL)'
The 'strict_flex_array' attribute should be attached to the trailing
array field of a structure. It controls when to treat the trailing array
field of a structure as a flexible array member for the purposes of accessing
the elements of such an array. LEVEL must be an integer betwen 0 to 3.
LEVEL=0 is the least strict level, all trailing arrays of
structures are treated as flexible array members. LEVEL=3 is the
strictest level, only when the trailing array is declared as a
flexible array member per C99 standard onwards ('[]'), it is
treated as a flexible array member.
There are two more levels in between 0 and 3, which are provided to
support older codes that use GCC zero-length array extension
('[0]') or one-element array as flexible array members('[1]'): When
LEVEL is 1, the trailing array is treated as a flexible array member
when it is declared as either '[]', '[0]', or '[1]'; When
LEVEL is 2, the trailing array is treated as a flexible array member
when it is declared as either '[]', or '[0]'.
This attribute can be used with or without the
'-fstrict-flex-arrays'. When both the attribute and the option
present at the same time, the level of the strictness for the
specific trailing array field is determined by the attribute.
gcc/c-family/ChangeLog:
* c-attribs.cc (handle_strict_flex_array_attribute): New function.
(c_common_attribute_table): New item for strict_flex_array.
* c.opt: (fstrict-flex-arrays): New option.
(fstrict-flex-arrays=): New option.
gcc/c/ChangeLog:
* c-decl.cc (flexible_array_member_type_p): New function.
(one_element_array_type_p): Likewise.
(zero_length_array_type_p): Likewise.
(add_flexible_array_elts_to_size): Call new utility
routine flexible_array_member_type_p.
(is_flexible_array_member_p): New function.
(finish_struct): Set the new DECL_NOT_FLEXARRAY flag.
gcc/cp/ChangeLog:
* module.cc (trees_out::core_bools): Stream out new bit
decl_not_flexarray.
(trees_in::core_bools): Stream in new bit decl_not_flexarray.
gcc/ChangeLog:
* doc/extend.texi: Document strict_flex_array attribute.
* doc/invoke.texi: Document -fstrict-flex-arrays[=n] option.
* print-tree.cc (print_node): Print new bit decl_not_flexarray.
* tree-core.h (struct tree_decl_common): New bit field
decl_not_flexarray.
* tree-streamer-in.cc (unpack_ts_decl_common_value_fields): Stream
in new bit decl_not_flexarray.
* tree-streamer-out.cc (pack_ts_decl_common_value_fields): Stream
out new bit decl_not_flexarray.
* tree.cc (array_at_struct_end_p): Update it with the new bit field
decl_not_flexarray.
* tree.h (DECL_NOT_FLEXARRAY): New flag.
gcc/testsuite/ChangeLog:
* g++.dg/strict-flex-array-1.C: New test.
* gcc.dg/strict-flex-array-1.c: New test.
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/c-decl.cc | 130 |
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; |