From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) by sourceware.org (Postfix) with ESMTPS id 79768385841D for ; Thu, 28 Jul 2022 07:26:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 79768385841D Received: from relay2.suse.de (relay2.suse.de [149.44.160.134]) by smtp-out1.suse.de (Postfix) with ESMTP id 04D3A34B0F; Thu, 28 Jul 2022 07:26:58 +0000 (UTC) Received: from wotan.suse.de (wotan.suse.de [10.160.0.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by relay2.suse.de (Postfix) with ESMTPS id 5DDEA2C143; Thu, 28 Jul 2022 07:26:52 +0000 (UTC) Date: Thu, 28 Jul 2022 07:26:57 +0000 (UTC) From: Richard Biener To: Qing Zhao cc: gcc-patches Paul A Clarke via , jakub Jelinek , martin Sebor , kees Cook , "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 In-Reply-To: Message-ID: References: User-Agent: Alpine 2.22 (LSU 394 2020-01-19) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII X-Spam-Status: No, score=-10.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Jul 2022 07:27:03 -0000 On Tue, 19 Jul 2022, Qing Zhao wrote: > From 3854004802b8e2f132ebf218fc35a632f5e80c6a Mon Sep 17 00:00:00 2001 > From: Qing Zhao > 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= 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 SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman; HRB 36809 (AG Nuernberg)