From: Richard Biener <rguenther@suse.de>
To: Qing Zhao <qing.zhao@oracle.com>
Cc: gcc-patches Paul A Clarke via <gcc-patches@gcc.gnu.org>,
jakub Jelinek <jakub@redhat.com>,
martin Sebor <msebor@gmail.com>,
kees Cook <keescook@chromium.org>,
"joseph@codesourcery.com" <joseph@codesourcery.com>
Subject: Re: [GCC13][Patch][V2][1/2]Add a new option -fstrict-flex-array[=n] and attribute strict_flex_array(n) and use it in PR101836
Date: Thu, 28 Jul 2022 07:26:57 +0000 (UTC) [thread overview]
Message-ID: <nycvar.YFH.7.77.849.2207280709260.6583@jbgna.fhfr.qr> (raw)
In-Reply-To: <EEE00E36-8AB0-4173-B711-C8836FECA1B9@oracle.com>
On Tue, 19 Jul 2022, Qing Zhao wrote:
> From 3854004802b8e2f132ebf218fc35a632f5e80c6a Mon Sep 17 00:00:00 2001
> From: Qing Zhao <qing.zhao@oracle.com>
> Date: Mon, 18 Jul 2022 17:04:12 +0000
> Subject: [PATCH 1/2] Add a new option -fstrict-flex-array[=n] and new
> attribute strict_flex_array
>
> Add the following new option -fstrict-flex-array[=n] and a corresponding
> attribute strict_flex_array to GCC:
>
> '-fstrict-flex-array'
> Treat the trailing array of a structure as a flexible array member
> in a stricter way. The positive form is equivalent to
> '-fstrict-flex-array=3', which is the strictest. A trailing array
> is treated as a flexible array member only when it is declared as a
> flexible array member per C99 standard onwards. The negative form
> is equivalent to '-fstrict-flex-array=0', which is the least
> strict. All trailing arrays of structures are treated as flexible
> array members.
>
> '-fstrict-flex-array=LEVEL'
> Treat the trailing array of a structure as a flexible array member
> in a stricter way. 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 specifies the level of
> strictness of treating the trailing array field of a structure as a
> flexible array member. 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-size array as flexible array member ([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 '-fstrict-flex-array'.
> 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-array): New option.
> (fstrict-flex-array=): New option.
>
> gcc/c/ChangeLog:
>
> * c-decl.cc (add_flexible_array_elts_to_size): Call new utility
> routine flexible_array_member_p.
> (is_flexible_array_member_p): New function.
> (finish_struct): Set the new DECL_NOT_FLEXARRAY flag.
>
> gcc/ChangeLog:
>
> * doc/extend.texi: Document strict_flex_array attribute.
> * doc/invoke.texi: Document -fstrict-flex-array[=n] option.
> * tree-core.h (struct tree_decl_common): New bit field
> decl_not_flexarray.
> * tree.cc (component_ref_size): Reorg by using new utility functions.
> (flexible_array_member_p): New function.
> (zero_length_array_p): Likewise.
> (one_element_array_p): Likewise.
> (flexible_array_type_p): Likewise.
> * tree.h (DECL_NOT_FLEXARRAY): New flag.
> (zero_length_array_p): New function prototype.
> (one_element_array_p): Likewise.
> (flexible_array_member_p): Likewise.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.dg/strict-flex-array-1.c: New test.
> ---
> gcc/c-family/c-attribs.cc | 47 ++++++++
> gcc/c-family/c.opt | 7 ++
> gcc/c/c-decl.cc | 91 +++++++++++++--
> gcc/doc/extend.texi | 25 ++++
> gcc/doc/invoke.texi | 27 ++++-
> gcc/testsuite/gcc.dg/strict-flex-array-1.c | 31 +++++
> gcc/tree-core.h | 5 +-
> gcc/tree.cc | 130 ++++++++++++++-------
> gcc/tree.h | 16 ++-
> 9 files changed, 322 insertions(+), 57 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-1.c
>
> diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
> index c8d96723f4c..10d16532f0d 100644
> --- a/gcc/c-family/c-attribs.cc
> +++ b/gcc/c-family/c-attribs.cc
> @@ -101,6 +101,8 @@ static tree handle_special_var_sec_attribute (tree *, tree, tree, int, bool *);
> static tree handle_aligned_attribute (tree *, tree, tree, int, bool *);
> static tree handle_warn_if_not_aligned_attribute (tree *, tree, tree,
> int, bool *);
> +static tree handle_strict_flex_array_attribute (tree *, tree, tree,
> + int, bool *);
> static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
> static tree handle_noplt_attribute (tree *, tree, tree, int, bool *) ;
> static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *);
> @@ -367,6 +369,8 @@ const struct attribute_spec c_common_attribute_table[] =
> attr_aligned_exclusions },
> { "warn_if_not_aligned", 0, 1, false, false, false, false,
> handle_warn_if_not_aligned_attribute, NULL },
> + { "strict_flex_array", 1, 1, false, false, false, false,
> + handle_strict_flex_array_attribute, NULL },
> { "weak", 0, 0, true, false, false, false,
> handle_weak_attribute, NULL },
> { "noplt", 0, 0, true, false, false, false,
> @@ -2498,6 +2502,49 @@ handle_warn_if_not_aligned_attribute (tree *node, tree name,
> no_add_attrs, true);
> }
>
> +/* Handle a "strict_flex_array" attribute; arguments as in
> + struct attribute_spec.handler. */
> +
> +static tree
> +handle_strict_flex_array_attribute (tree *node, tree name,
> + tree args, int ARG_UNUSED (flags),
> + bool *no_add_attrs)
> +{
> + tree decl = *node;
> + tree argval = TREE_VALUE (args);
> +
> + /* This attribute only applies to field decls of a structure. */
> + if (TREE_CODE (decl) != FIELD_DECL)
> + {
> + error_at (DECL_SOURCE_LOCATION (decl),
> + "%qE attribute may not be specified for %q+D", name, decl);
> + *no_add_attrs = true;
> + }
> + /* This attribute only applies to field with array type. */
> + else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE)
> + {
> + error_at (DECL_SOURCE_LOCATION (decl),
> + "%qE attribute may not be specified for a non array field",
> + name);
> + *no_add_attrs = true;
> + }
> + else if (TREE_CODE (argval) != INTEGER_CST)
> + {
> + error_at (DECL_SOURCE_LOCATION (decl),
> + "%qE attribute argument not an integer", name);
> + *no_add_attrs = true;
> + }
> + else if (!tree_fits_uhwi_p (argval) || tree_to_uhwi (argval) > 3)
> + {
> + error_at (DECL_SOURCE_LOCATION (decl),
> + "%qE attribute argument %qE is not an integer constant"
> + " between 0 and 3", name, argval);
> + *no_add_attrs = true;
> + }
> +
> + return NULL_TREE;
> +}
> +
> /* Handle a "weak" attribute; arguments as in
> struct attribute_spec.handler. */
>
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 44e1a60ce24..864cd8df1d3 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -2060,6 +2060,13 @@ fsized-deallocation
> C++ ObjC++ Var(flag_sized_deallocation) Init(-1)
> Enable C++14 sized deallocation support.
>
> +fstrict-flex-array
> +C C++ Common Alias(fstrict-flex-array=,3,0)
> +
> +fstrict-flex-array=
> +C C++ Common Joined RejectNegative UInteger Var(flag_strict_flex_array) Init(0) IntegerRange(0,3)
> +-fstrict-flex-array=<level> Treat the trailing array of a structure as a flexible array in a stricter way. The default is treating all trailing arrays of structures as flexible arrays.
> +
> fsquangle
> C++ ObjC++ WarnRemoved
>
> diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> index ae8990c138f..14defae9584 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -5013,10 +5013,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_p (type))
> {
> complete_array_type (&type, elt, false);
> DECL_SIZE (decl)
> @@ -8720,6 +8717,80 @@ 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_array;
> + 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_p (TREE_TYPE (x));
> + bool is_one_element_array = one_element_array_p (TREE_TYPE (x));
> + bool is_flexible_array = flexible_array_member_p (TREE_TYPE (x));
> +
> + unsigned int strict_flex_array_level = flag_strict_flex_array;
> +
> + 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_array. */
> + 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 flexiable array members. */
> + return true;
> + case 1:
> + /* Level 1: all "[1]", "[0]", and "[]" are flexiable array members. */
> + if (is_one_element_array)
> + return true;
> + /* FALLTHROUGH. */
> + case 2:
> + /* Level 2: all "[0]", and "[]" are flexiable 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.
> @@ -8781,6 +8852,8 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
> bool saw_named_field = false;
> for (x = fieldlist; x; x = DECL_CHAIN (x))
> {
> + bool is_last_field = (DECL_CHAIN (x) == NULL_TREE);
> +
> if (TREE_TYPE (x) == error_mark_node)
> continue;
>
> @@ -8819,10 +8892,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_p (TREE_TYPE (x)))
> {
> if (TREE_CODE (t) == UNION_TYPE)
> {
> @@ -8830,7 +8900,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");
> @@ -8850,6 +8920,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;
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index dfbe33ac652..7451410a011 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -7436,6 +7436,31 @@ This warning can be disabled by @option{-Wno-if-not-aligned}.
> The @code{warn_if_not_aligned} attribute can also be used for types
> (@pxref{Common Type Attributes}.)
>
> +@cindex @code{strict_flex_array} variable attribute
> +@item strict_flex_array (@var{level})
> +The @code{strict_flex_array} attribute should be attached to the trailing
> +array field of a structure. It specifies the level of strictness of
> +treating the trailing array field of a structure as a flexible array
> +member. @var{level} must be an integer betwen 0 to 3.
> +
> +@var{level}=0 is the least strict level, all trailing arrays of structures
> +are treated as flexible array members. @var{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.
How is level 3 (thus -fstrict-flex-array) interpreted when you specify
-std=c89? How for -std=gnu89?
> +
> +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-size array
> +as flexible array member ([1]):
> +When @var{level} is 1, the trailing array is treated as a flexible array member
> +when it is declared as either "[]", "[0]", or "[1]";
> +When @var{level} is 2, the trailing array is treated as a flexible array member
> +when it is declared as either "[]", or "[0]".
Given the above does adding level 2 make sense given that [0] is a GNU
extension?
> +This attribute can be used with or without @option{-fstrict-flex-array}. 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.
> +
> +
> @item alloc_size (@var{position})
> @itemx alloc_size (@var{position-1}, @var{position-2})
> @cindex @code{alloc_size} variable attribute
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 94fe57aa4e2..9befe601817 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -207,7 +207,8 @@ in the following sections.
> -fopenmp -fopenmp-simd @gol
> -fpermitted-flt-eval-methods=@var{standard} @gol
> -fplan9-extensions -fsigned-bitfields -funsigned-bitfields @gol
> --fsigned-char -funsigned-char -fsso-struct=@var{endianness}}
> +-fsigned-char -funsigned-char -fstrict-flex-array[=@var{n}] @gol
> +-fsso-struct=@var{endianness}}
>
> @item C++ Language Options
> @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
> @@ -2825,6 +2826,30 @@ The type @code{char} is always a distinct type from each of
> @code{signed char} or @code{unsigned char}, even though its behavior
> is always just like one of those two.
>
> +@item -fstrict-flex-array
> +@opindex fstrict-flex-array
> +@opindex fno-strict-flex-array
> +Treat the trailing array of a structure as a flexible array member in a
> +stricter way.
> +The positive form is equivalent to @option{-fstrict-flex-array=3}, which is the
> +strictest. A trailing array is treated as a flexible array member only when it
> +is declared as a flexible array member per C99 standard onwards.
> +The negative form is equivalent to @option{-fstrict-flex-array=0}, which is the
> +least strict. All trailing arrays of structures are treated as flexible array
> +members.
> +
> +@item -fstrict-flex-array=@var{level}
> +@opindex fstrict-flex-array=@var{level}
> +Treat the trailing array of a structure as a flexible array member in a
> +stricter way. The value of @var{level} controls the level of strictness.
> +
> +The possible values of @var{level} are the same as for the
> +@code{strict_flex_array} attribute (@pxref{Variable Attributes}).
> +
> +You can control this behavior for a specific trailing array field of a
> +structure by using the variable attribute @code{strict_flex_array} attribute
> +(@pxref{Variable Attributes}).
> +
> @item -fsso-struct=@var{endianness}
> @opindex fsso-struct
> Set the default scalar storage order of structures and unions to the
> diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-1.c b/gcc/testsuite/gcc.dg/strict-flex-array-1.c
> new file mode 100644
> index 00000000000..ec886c99b25
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/strict-flex-array-1.c
> @@ -0,0 +1,31 @@
> +/* testing the correct usage of attribute strict_flex_array. */
> +/* { dg-do compile } */
> +/* { dg-options "-O2" } */
> +
> +
> +int x __attribute__ ((strict_flex_array (1))); /* { dg-error "'strict_flex_array' attribute may not be specified for 'x'" } */
> +
> +struct trailing {
> + int a;
> + int c __attribute ((strict_flex_array)); /* { dg-error "wrong number of arguments specified for 'strict_flex_array' attribute" } */
> +};
> +
> +struct trailing_1 {
> + int a;
> + int b;
> + int c __attribute ((strict_flex_array (2))); /* { dg-error "'strict_flex_array' attribute may not be specified for a non array field" } */
> +};
> +
> +extern int d;
> +
> +struct trailing_array_2 {
> + int a;
> + int b;
> + int c[1] __attribute ((strict_flex_array (d))); /* { dg-error "'strict_flex_array' attribute argument not an integer" } */
> +};
> +
> +struct trailing_array_3 {
> + int a;
> + int b;
> + int c[0] __attribute ((strict_flex_array (5))); /* { dg-error "'strict_flex_array' attribute argument '5' is not an integer constant between 0 and 3" } */
> +};
> diff --git a/gcc/tree-core.h b/gcc/tree-core.h
> index ea9f281f1cc..458c6e6ceea 100644
> --- a/gcc/tree-core.h
> +++ b/gcc/tree-core.h
> @@ -1813,7 +1813,10 @@ struct GTY(()) tree_decl_common {
> TYPE_WARN_IF_NOT_ALIGN. */
> unsigned int warn_if_not_align : 6;
>
> - /* 14 bits unused. */
> + /* In FIELD_DECL, this is DECL_NOT_FLEXARRAY. */
> + unsigned int decl_not_flexarray : 1;
> +
> + /* 13 bits unused. */
I've not seen it so you are probably missing it - the bit has to be
streamed in tree-streamer-{in,out}.cc to be usable from LTO. Possibly
C++ module streaming also needs to handle it.
>
> /* UID for points-to sets, stable over copying from inlining. */
> unsigned int pt_uid;
> diff --git a/gcc/tree.cc b/gcc/tree.cc
> index 84000dd8b69..02e274699fb 100644
> --- a/gcc/tree.cc
> +++ b/gcc/tree.cc
> @@ -12862,7 +12862,7 @@ get_initializer_for (tree init, tree decl)
> /* Determines the size of the member referenced by the COMPONENT_REF
> REF, using its initializer expression if necessary in order to
> determine the size of an initialized flexible array member.
> - If non-null, set *ARK when REF refers to an interior zero-length
> + If non-null, set *SAM when REF refers to an interior zero-length
> array or a trailing one-element array.
> Returns the size as sizetype (which might be zero for an object
> with an uninitialized flexible array member) or null if the size
> @@ -12878,16 +12878,32 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
> sam = &sambuf;
> *sam = special_array_member::none;
>
> + /* Whether this ref is an array at the end of a structure. */
> + bool trailing = array_at_struct_end_p (ref);
> +
actually array_at_struct_end_p returns whether ref possibly refers to
a trailing array. In particular it may return false for arrays at
struct end with a known length as in a.b[i] for the reference to global
'a':
struct { int b[1]; } a;
so in the end it should be array_at_struct_end_p also honoring
DECL_NOT_FLEXARRAY.
> /* The object/argument referenced by the COMPONENT_REF and its type. */
> tree arg = TREE_OPERAND (ref, 0);
> tree argtype = TREE_TYPE (arg);
> - /* The referenced member. */
> - tree member = TREE_OPERAND (ref, 1);
>
> + /* The referenced field member. */
> + tree member = TREE_OPERAND (ref, 1);
> + tree memtype = TREE_TYPE (member);
> tree memsize = DECL_SIZE_UNIT (member);
> +
> + bool is_zero_length_array_ref = zero_length_array_p (memtype);
> + bool is_constant_length_array_ref = false;
> + bool is_one_element_array_ref
> + = one_element_array_p (memtype, &is_constant_length_array_ref);
> +
> + /* Determine the type of the special array member. */
> + if (is_zero_length_array_ref)
> + *sam = trailing ? special_array_member::trail_0
> + : special_array_member::int_0;
> + else if (is_one_element_array_ref && trailing)
> + *sam = special_array_member::trail_1;
> +
> if (memsize)
> {
> - tree memtype = TREE_TYPE (member);
> if (TREE_CODE (memtype) != ARRAY_TYPE)
> /* DECL_SIZE may be less than TYPE_SIZE in C++ when referring
> to the type of a class with a virtual base which doesn't
> @@ -12897,50 +12913,30 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
> return (tree_int_cst_equal (memsize, TYPE_SIZE_UNIT (memtype))
> ? memsize : NULL_TREE);
>
> - bool trailing = array_at_struct_end_p (ref);
> - bool zero_length = integer_zerop (memsize);
> - if (!trailing && !zero_length)
> + if (!trailing && !is_zero_length_array_ref)
> /* MEMBER is either an interior array or is an array with
> more than one element. */
> return memsize;
>
> - if (zero_length)
> - {
> - if (trailing)
> - *sam = special_array_member::trail_0;
> - else
> - {
> - *sam = special_array_member::int_0;
> - memsize = NULL_TREE;
> - }
> - }
> + if (*sam != special_array_member::trail_1
> + && is_constant_length_array_ref)
> + /* MEMBER is a constant length array which is not a one-element
> + trailing array. */
> + return memsize;
>
> - if (!zero_length)
> - if (tree dom = TYPE_DOMAIN (memtype))
> - if (tree min = TYPE_MIN_VALUE (dom))
> - if (tree max = TYPE_MAX_VALUE (dom))
> - if (TREE_CODE (min) == INTEGER_CST
> - && TREE_CODE (max) == INTEGER_CST)
> - {
> - offset_int minidx = wi::to_offset (min);
> - offset_int maxidx = wi::to_offset (max);
> - offset_int neltsm1 = maxidx - minidx;
> - if (neltsm1 > 0)
> - /* MEMBER is an array with more than one element. */
> - return memsize;
> -
> - if (neltsm1 == 0)
> - *sam = special_array_member::trail_1;
> - }
> + if (*sam == special_array_member::int_0)
> + memsize = NULL_TREE;
>
> - /* For a reference to a zero- or one-element array member of a union
> - use the size of the union instead of the size of the member. */
> + /* For a reference to a flexible array member, an interior zero length
> + array, or an array with variable length of a union, use the size of
> + the union instead of the size of the member. */
> if (TREE_CODE (argtype) == UNION_TYPE)
> memsize = TYPE_SIZE_UNIT (argtype);
> }
>
> - /* MEMBER is either a bona fide flexible array member, or a zero-length
> - array member, or an array of length one treated as such. */
> + /* MEMBER now is a flexible array member, an interior zero length array, or
> + an array with variable length. We need to decide its size from its
> + initializer. */
>
> /* If the reference is to a declared object and the member a true
> flexible array, try to determine its size from its initializer. */
> @@ -14351,6 +14347,59 @@ default_is_empty_record (const_tree type)
> return is_empty_type (TYPE_MAIN_VARIANT (type));
> }
>
> +/* Determine whether TYPE is a ISO flexible array memeber type "[]". */
ISO C99
> +bool
> +flexible_array_member_p (const_tree type)
since you pass in a type a better name would be
flexible_array_type_p?
> +{
> + if (TREE_CODE (type) == ARRAY_TYPE
> + && TYPE_SIZE (type) == NULL_TREE
> + && TYPE_DOMAIN (type) != NULL_TREE
why require a specified TYPE_DOMAIN?
> + && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
and why a NULL TYPE_MAX_VALUE? Isn't an unknown TYPE_SIZE enough?
That said, I'm not sure providing this abstraction is a good idea
given the use I see is in frontend code.
> + return true;
> +
> + return false;
> +}
> +
> +/* Determine whether TYPE is a zero-length array type "[0]". */
> +bool
> +zero_length_array_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)
that again seems very C(?) frontend specific, please drop it.
> + return true;
> + return false;
> +}
> +
> +/* Determine whether TYPE is a one-element array type "[1]".
> + Set IS_CONSTANT_LENGTH to true if the length is constant,
> + otherwise, IS_CONSTANT_LENGTH is set to false. */
> +bool
> +one_element_array_p (const_tree type, bool *is_constant_length /* = NULL */)
> +{
> + if (is_constant_length)
> + *is_constant_length = false;
> +
> + if (TREE_CODE (type) == ARRAY_TYPE)
> + if (tree dom = TYPE_DOMAIN (type))
> + if (tree min = TYPE_MIN_VALUE (dom))
> + if (tree max = TYPE_MAX_VALUE (dom))
> + if (TREE_CODE (min) == INTEGER_CST
> + && TREE_CODE (max) == INTEGER_CST)
> + {
> + offset_int minidx = wi::to_offset (min);
> + offset_int maxidx = wi::to_offset (max);
> + offset_int neltsm1 = maxidx - minidx;
> + if (is_constant_length)
> + *is_constant_length = true;
> + if (neltsm1 == 0)
> + return true;
> + }
I'd say likewise. Maybe move them to c-family/c-common.{cc,h} instead
in a more specialized way for the single use you have?
> + return false;
> +}
> +
> /* Determine whether TYPE is a structure with a flexible array member,
> or a union containing such a structure (possibly recursively). */
>
> @@ -14367,10 +14416,7 @@ flexible_array_type_p (const_tree type)
> last = x;
> if (last == NULL_TREE)
> return false;
> - if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
> - && TYPE_SIZE (TREE_TYPE (last)) == NULL_TREE
> - && TYPE_DOMAIN (TREE_TYPE (last)) != NULL_TREE
> - && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (last))) == NULL_TREE)
> + if (flexible_array_member_p (TREE_TYPE (last)))
> return true;
> return false;
> case UNION_TYPE:
> diff --git a/gcc/tree.h b/gcc/tree.h
> index e6564aaccb7..3107de5b499 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -2993,6 +2993,11 @@ extern void decl_value_expr_insert (tree, tree);
> #define DECL_PADDING_P(NODE) \
> (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_3)
>
> +/* Used in a FIELD_DECL to indicate whether this field is not a flexible
> + array member. */
> +#define DECL_NOT_FLEXARRAY(NODE) \
> + (FIELD_DECL_CHECK (NODE)->decl_common.decl_not_flexarray)
> +
> /* A numeric unique identifier for a LABEL_DECL. The UID allocation is
> dense, unique within any one function, and may be used to index arrays.
> If the value is -1, then no UID has been assigned. */
> @@ -5531,10 +5536,10 @@ extern tree component_ref_field_offset (tree);
> returns null. */
> enum struct special_array_member
> {
> - none, /* Not a special array member. */
> - int_0, /* Interior array member with size zero. */
> - trail_0, /* Trailing array member with size zero. */
> - trail_1 /* Trailing array member with one element. */
> + none, /* Not a special array member. */
> + int_0, /* Interior array member with size zero. */
> + trail_0, /* Trailing array member with size zero. */
> + trail_1 /* Trailing array member with one element. */
> };
>
> /* Return the size of the member referenced by the COMPONENT_REF, using
> @@ -6489,6 +6494,9 @@ extern void gt_pch_nx (tree &, gt_pointer_operator, void *);
> extern bool nonnull_arg_p (const_tree);
> extern bool is_empty_type (const_tree);
> extern bool default_is_empty_record (const_tree);
> +extern bool zero_length_array_p (const_tree);
> +extern bool one_element_array_p (const_tree, bool * = NULL);
> +extern bool flexible_array_member_p (const_tree);
> extern bool flexible_array_type_p (const_tree);
> extern HOST_WIDE_INT arg_int_size_in_bytes (const_tree);
> extern tree arg_size_in_bytes (const_tree);
>
--
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
HRB 36809 (AG Nuernberg)
next prev parent reply other threads:[~2022-07-28 7:26 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-07-19 14:09 Qing Zhao
2022-07-27 22:39 ` Kees Cook
2022-07-28 7:26 ` Richard Biener [this message]
2022-07-29 5:44 ` Kees Cook
2022-07-29 6:20 ` Richard Biener
2022-07-29 19:56 ` Qing Zhao
2022-08-01 7:38 ` Richard Biener
2022-08-01 15:32 ` Qing Zhao
2022-08-02 7:03 ` Richard Biener
2022-08-02 14:06 ` Qing Zhao
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=nycvar.YFH.7.77.849.2207280709260.6583@jbgna.fhfr.qr \
--to=rguenther@suse.de \
--cc=gcc-patches@gcc.gnu.org \
--cc=jakub@redhat.com \
--cc=joseph@codesourcery.com \
--cc=keescook@chromium.org \
--cc=msebor@gmail.com \
--cc=qing.zhao@oracle.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).