Ping * 2. FYI: this feature has been committed into CLANG on 5/13/2025:
https://github.com/llvm/llvm-project/pull/137250 Thanks a lot for your review. Qing > On May 13, 2025, at 17:03, Qing Zhao <qing.z...@oracle.com> wrote: > > For example: > struct PP { > size_t count2; > char other1; > char *array2 __attribute__ ((counted_by (count2))); > int other2; > } *pp; > > specifies that the "array2" is an array that is pointed by the > pointer field, and its number of elements is given by the field > "count2" in the same structure. > > gcc/c-family/ChangeLog: > > * c-attribs.cc (handle_counted_by_attribute): Accept counted_by > attribute for pointer fields. > > gcc/c/ChangeLog: > > * c-decl.cc (verify_counted_by_attribute): Change the 2nd argument > to a vector of fields with counted_by attribute. Verify all fields > in this vector. > (finish_struct): Collect all the fields with counted_by attribute > to a vector and pass this vector to verify_counted_by_attribute. > > gcc/ChangeLog: > > * doc/extend.texi: Extend counted_by attribute to pointer fields in > structures. Add one more requirement to pointers with counted_by > attribute. > > gcc/testsuite/ChangeLog: > > * gcc.dg/flex-array-counted-by.c: Update test. > * gcc.dg/pointer-counted-by-2.c: New test. > * gcc.dg/pointer-counted-by-3.c: New test. > * gcc.dg/pointer-counted-by.c: New test. > --- > gcc/c-family/c-attribs.cc | 25 +++- > gcc/c/c-decl.cc | 91 +++++++------ > gcc/doc/extend.texi | 38 +++++- > gcc/testsuite/gcc.dg/flex-array-counted-by.c | 2 +- > gcc/testsuite/gcc.dg/pointer-counted-by-2.c | 10 ++ > gcc/testsuite/gcc.dg/pointer-counted-by-3.c | 127 +++++++++++++++++++ > gcc/testsuite/gcc.dg/pointer-counted-by.c | 73 +++++++++++ > 7 files changed, 315 insertions(+), 51 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/pointer-counted-by-2.c > create mode 100644 gcc/testsuite/gcc.dg/pointer-counted-by-3.c > create mode 100644 gcc/testsuite/gcc.dg/pointer-counted-by.c > > diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc > index 5a0e3d328ba..717133afc59 100644 > --- a/gcc/c-family/c-attribs.cc > +++ b/gcc/c-family/c-attribs.cc > @@ -2906,22 +2906,34 @@ handle_counted_by_attribute (tree *node, tree name, > " declaration %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) > + /* This attribute only applies to field with array type or pointer type. > */ > + else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE > + && TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE) > { > error_at (DECL_SOURCE_LOCATION (decl), > - "%qE attribute is not allowed for a non-array field", > - name); > + "%qE attribute is not allowed for a non-array" > + " or non-pointer field", name); > *no_add_attrs = true; > } > /* This attribute only applies to a C99 flexible array member type. */ > - else if (! c_flexible_array_member_type_p (TREE_TYPE (decl))) > + else if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE > + && !c_flexible_array_member_type_p (TREE_TYPE (decl))) > { > error_at (DECL_SOURCE_LOCATION (decl), > "%qE attribute is not allowed for a non-flexible" > " array member field", name); > *no_add_attrs = true; > } > + /* This attribute cannot be applied to a pointer type whose pointee type > + is void. */ > + else if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE > + && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == VOID_TYPE) > + { > + error_at (DECL_SOURCE_LOCATION (decl), > + "%qE attribute is not allowed for a pointer field" > + " with void pointee type", name); > + *no_add_attrs = true; > + } > /* The argument should be an identifier. */ > else if (TREE_CODE (argval) != IDENTIFIER_NODE) > { > @@ -2930,7 +2942,8 @@ handle_counted_by_attribute (tree *node, tree name, > *no_add_attrs = true; > } > /* Issue error when there is a counted_by attribute with a different > - field as the argument for the same flexible array member field. */ > + field as the argument for the same flexible array member or > + pointer field. */ > else if (old_counted_by != NULL_TREE) > { > tree old_fieldname = TREE_VALUE (TREE_VALUE (old_counted_by)); > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc > index 8c420f22976..53e7b726ee6 100644 > --- a/gcc/c/c-decl.cc > +++ b/gcc/c/c-decl.cc > @@ -9448,56 +9448,62 @@ c_update_type_canonical (tree t) > } > } > > -/* Verify the argument of the counted_by attribute of the flexible array > - member FIELD_DECL is a valid field of the containing structure, > - STRUCT_TYPE, Report error and remove this attribute when it's not. */ > +/* Verify the argument of the counted_by attribute of each of the > + FIELDS_WITH_COUNTED_BY is a valid field of the containing structure, > + STRUCT_TYPE, Report error and remove the corresponding attribute > + when it's not. */ > > static void > -verify_counted_by_attribute (tree struct_type, tree field_decl) > +verify_counted_by_attribute (tree struct_type, > + auto_vec<tree> *fields_with_counted_by) > { > - tree attr_counted_by = lookup_attribute ("counted_by", > - DECL_ATTRIBUTES (field_decl)); > - > - if (!attr_counted_by) > - return; > + for (tree field_decl : *fields_with_counted_by) > + { > + tree attr_counted_by = lookup_attribute ("counted_by", > + DECL_ATTRIBUTES (field_decl)); > > - /* If there is an counted_by attribute attached to the field, > - verify it. */ > + if (!attr_counted_by) > + continue; > > - tree fieldname = TREE_VALUE (TREE_VALUE (attr_counted_by)); > + /* If there is an counted_by attribute attached to the field, > + verify it. */ > > - /* Verify the argument of the attrbute is a valid field of the > - containing structure. */ > + tree fieldname = TREE_VALUE (TREE_VALUE (attr_counted_by)); > > - tree counted_by_field = lookup_field (struct_type, fieldname); > + /* Verify the argument of the attrbute is a valid field of the > + containing structure. */ > > - /* Error when the field is not found in the containing structure and > - remove the corresponding counted_by attribute from the field_decl. */ > - if (!counted_by_field) > - { > - error_at (DECL_SOURCE_LOCATION (field_decl), > - "argument %qE to the %<counted_by%> attribute" > - " is not a field declaration in the same structure" > - " as %qD", fieldname, field_decl); > - DECL_ATTRIBUTES (field_decl) > - = remove_attribute ("counted_by", DECL_ATTRIBUTES (field_decl)); > - } > - else > - /* Error when the field is not with an integer type. */ > - { > - while (TREE_CHAIN (counted_by_field)) > - counted_by_field = TREE_CHAIN (counted_by_field); > - tree real_field = TREE_VALUE (counted_by_field); > + tree counted_by_field = lookup_field (struct_type, fieldname); > > - if (!INTEGRAL_TYPE_P (TREE_TYPE (real_field))) > + /* Error when the field is not found in the containing structure and > + remove the corresponding counted_by attribute from the field_decl. */ > + if (!counted_by_field) > { > error_at (DECL_SOURCE_LOCATION (field_decl), > "argument %qE to the %<counted_by%> attribute" > - " is not a field declaration with an integer type", > - fieldname); > + " is not a field declaration in the same structure" > + " as %qD", fieldname, field_decl); > DECL_ATTRIBUTES (field_decl) > = remove_attribute ("counted_by", DECL_ATTRIBUTES (field_decl)); > } > + else > + /* Error when the field is not with an integer type. */ > + { > + while (TREE_CHAIN (counted_by_field)) > + counted_by_field = TREE_CHAIN (counted_by_field); > + tree real_field = TREE_VALUE (counted_by_field); > + > + if (!INTEGRAL_TYPE_P (TREE_TYPE (real_field))) > + { > + error_at (DECL_SOURCE_LOCATION (field_decl), > + "argument %qE to the %<counted_by%> attribute" > + " is not a field declaration with an integer type", > + fieldname); > + DECL_ATTRIBUTES (field_decl) > + = remove_attribute ("counted_by", > + DECL_ATTRIBUTES (field_decl)); > + } > + } > } > } > > @@ -9572,7 +9578,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, > tree attributes, > until now.) */ > > bool saw_named_field = false; > - tree counted_by_fam_field = NULL_TREE; > + auto_vec<tree> fields_with_counted_by; > for (x = fieldlist; x; x = DECL_CHAIN (x)) > { > /* Whether this field is the last field of the structure or union. > @@ -9653,9 +9659,16 @@ finish_struct (location_t loc, tree t, tree fieldlist, > tree attributes, > record it here and do more verification later after the > whole structure is complete. */ > if (lookup_attribute ("counted_by", DECL_ATTRIBUTES (x))) > - counted_by_fam_field = x; > + fields_with_counted_by.safe_push (x); > } > > + if (TREE_CODE (TREE_TYPE (x)) == POINTER_TYPE) > + /* If there is a counted_by attribute attached to this field, > + record it here and do more verification later after the > + whole structure is complete. */ > + if (lookup_attribute ("counted_by", DECL_ATTRIBUTES (x))) > + fields_with_counted_by.safe_push (x); > + > if (pedantic && TREE_CODE (t) == RECORD_TYPE > && flexible_array_type_p (TREE_TYPE (x))) > pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic, > @@ -9945,8 +9958,8 @@ finish_struct (location_t loc, tree t, tree fieldlist, > tree attributes, > struct_parse_info->struct_types.safe_push (t); > } > > - if (counted_by_fam_field) > - verify_counted_by_attribute (t, counted_by_fam_field); > + if (fields_with_counted_by.length () > 0) > + verify_counted_by_attribute (t, &fields_with_counted_by); > > return t; > } > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi > index 0978c4c41b2..6b432531e31 100644 > --- a/gcc/doc/extend.texi > +++ b/gcc/doc/extend.texi > @@ -7116,9 +7116,11 @@ The @code{aligned} attribute can also be used for > functions > @cindex @code{counted_by} variable attribute > @item counted_by (@var{count}) > The @code{counted_by} attribute may be attached to the C99 flexible array > -member of a structure. It indicates that the number of the elements of the > -array is given by the field "@var{count}" in the same structure as the > -flexible array member. > +member, or a pointer field of a structure. It indicates that the number > +of the elements of the array that is held by the flexible array member > +field, or is pointed to by the pointer field, is given by the field > +"@var{count}" in the same structure as the flexible array member or the > +pointer field. > > This attribute is available only in C for now. > In C++ this attribute is ignored. > @@ -7139,8 +7141,22 @@ struct P @{ > @end smallexample > > @noindent > -specifies that the @code{array} is a flexible array member whose number of > -elements is given by the field @code{count} in the same structure. > +specifies that the @code{array} is a flexible array member whose number > +of elements is given by the field @code{count} in the same structure. > + > +@smallexample > +struct PP @{ > + size_t count2; > + char other1; > + char *array2 __attribute__ ((counted_by (count2))); > + int other2; > +@} *pp; > +@end smallexample > + > +@noindent > +specifies that the @code{array2} is an array that is pointed by the > +pointer field, and its number of elements is given by the field > +@code{count2} in the same structure. > > The field that represents the number of the elements should have an > integer type. Otherwise, the compiler reports an error and ignores > @@ -7149,6 +7165,9 @@ the attribute. > When the field that represents the number of the elements is assigned a > negative integer value, the compiler treats the value as zero. > > +The counted_by attribute is not allowed for a pointer field whose pointee > +has type @code{void}. > + > An explicit @code{counted_by} annotation defines a relationship between > two objects, @code{p->array} and @code{p->count}, and there are the > following requirements on the relationship between this pair: > @@ -7164,6 +7183,13 @@ available all the time. This relationship must hold > even after any of > these related objects are updated during the program. > @end itemize > > +In addition to the above requirements, there is one more requirement > +between this pair if and only if @code{p->array} is an array that is > +pointed by the pointer field: > + > +@code{p->array} and @code{p->count} can only be changed by changing the > +whole structure at the same time. > + > It's the programmer's responsibility to make sure the above requirements to > be kept all the time. Otherwise the compiler reports warnings and > the results of the array bound sanitizer and the > @@ -7185,6 +7211,8 @@ In the above, @code{ref1} uses @code{val1} as the > number of the elements in > @code{p->array}, and @code{ref2} uses @code{val2} as the number of elements > in @code{p->array}. > > +Note, however, the above feature is not valid for the pointer field. > + > @cindex @code{alloc_size} variable attribute > @item alloc_size (@var{position}) > @itemx alloc_size (@var{position-1}, @var{position-2}) > diff --git a/gcc/testsuite/gcc.dg/flex-array-counted-by.c > b/gcc/testsuite/gcc.dg/flex-array-counted-by.c > index 16eb2c63010..4fa91ff0bdb 100644 > --- a/gcc/testsuite/gcc.dg/flex-array-counted-by.c > +++ b/gcc/testsuite/gcc.dg/flex-array-counted-by.c > @@ -10,7 +10,7 @@ int x __attribute ((counted_by (size))); /* { dg-error > "attribute is not allowed > > struct trailing { > int count; > - int field __attribute ((counted_by (count))); /* { dg-error "attribute is > not allowed for a non-array field" } */ > + int field __attribute ((counted_by (count))); /* { dg-error "attribute is > not allowed for a non-array or non-pointer field" } */ > }; > > struct trailing_1 { > diff --git a/gcc/testsuite/gcc.dg/pointer-counted-by-2.c > b/gcc/testsuite/gcc.dg/pointer-counted-by-2.c > new file mode 100644 > index 00000000000..1f4a278052c > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pointer-counted-by-2.c > @@ -0,0 +1,10 @@ > +/* Testing the correct usage of attribute counted_by for pointer: _BitInt */ > +/* { dg-do compile { target bitint } } */ > +/* { dg-options "-O2 -std=c23" } */ > + > +struct pointer_array { > + _BitInt(24) count; > + int *array __attribute__ ((counted_by (count))); > + int *array1 __attribute__ ((counted_by (count1))); > + _BitInt(24) count1; > +}; > diff --git a/gcc/testsuite/gcc.dg/pointer-counted-by-3.c > b/gcc/testsuite/gcc.dg/pointer-counted-by-3.c > new file mode 100644 > index 00000000000..70056098364 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pointer-counted-by-3.c > @@ -0,0 +1,127 @@ > + /* Testing the correct usage of attribute counted_by for pointer in c23, > + multiple definitions of the same tag in same or different scopes. > + { dg-do compile } > + { dg-options "-std=c23" } > + */ > + > +/* Allowed redefinitions of the same struct in the same scope, with the > + same counted_by attribute. */ > +struct f { > + int b; > + int c; > + int *a __attribute__ ((counted_by (b))); }; > +struct f { > + int b; > + int c; > + int *a __attribute__ ((counted_by (b))); }; > +struct f { > + int b; > + int c; > + int *a; }; /* { dg-error "redefinition of struct or union" } */ > + > +/* Error when the counted_by attribute is defined differently. */ > +struct f { > + int b; > + int c; > + int *a __attribute__ ((counted_by (c))); }; /* { dg-error "redefinition of > struct or union" } */ > + > +struct h { > + int b; > + int c; > + int *a __attribute__ ((counted_by (b))); } p; > + > +void test (void) > +{ > + struct h { > + int b; > + int c; > + int *a __attribute__ ((counted_by (b))); } x; > + > + p = x; > +} > + > +void test1 (void) > +{ > + struct h { > + int b; > + int c; > + int *a __attribute__ ((counted_by (c))); } y; > + > + p = y; /* { dg-error "incompatible types when assigning to type" } */ > +} > + > +struct nested_f { > + struct { > + union { > + int b; > + float f; > + }; > + int n; > + }; > + char *c __attribute__ ((counted_by (b))); > +}; > + > +struct nested_f { > + struct { > + union { > + int b; > + float f; > + }; > + int n; > + }; > + char *c __attribute__ ((counted_by (b))); > +}; > + > +struct nested_f { > + struct { > + union { > + int b; > + float f; > + }; > + int n; > + }; > + char *c __attribute__ ((counted_by (n))); > +}; /* { dg-error "redefinition of struct or union" } */ > + > +struct nested_h { > + struct { > + union { > + int b; > + float f; > + }; > + int n; > + }; > + char *c __attribute__ ((counted_by (b))); > +} nested_p; > + > +void test_2 (void) > +{ > +struct nested_h { > + struct { > + union { > + int b; > + float f; > + }; > + int n; > + }; > + char *c __attribute__ ((counted_by (b))); > +} nested_x; > + > + nested_p = nested_x; > +} > + > +void test_3 (void) > +{ > +struct nested_h { > + struct { > + union { > + int b; > + float f; > + }; > + int n; > + }; > + char *c __attribute__ ((counted_by (n))); > +} nested_y; > + > + nested_p = nested_y; /* { dg-error "incompatible types when assigning to > type" } */ > +} > diff --git a/gcc/testsuite/gcc.dg/pointer-counted-by.c > b/gcc/testsuite/gcc.dg/pointer-counted-by.c > new file mode 100644 > index 00000000000..ed323ceb79f > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pointer-counted-by.c > @@ -0,0 +1,73 @@ > +/* Testing the correct usage of attribute counted_by for pointer field. > + and also mixed pointer field and FMA field in the same structure. */ > +/* { dg-do compile } */ > +/* { dg-options "-O2" } */ > + > +int size; > +int *x __attribute__ ((counted_by (size))); /* { dg-error "attribute is not > allowed for a non-field declaration" } */ > + > +struct pointer_array_0 { > + int count; > + int array __attribute__ ((counted_by (count))); /* { dg-error "attribute > is not allowed for a non-array or non-pointer field" } */ > + int other; > +}; > + > +int count; > +struct pointer_array_1 { > + int other; > + int *array_1 __attribute__ ((counted_by (count))); /* { dg-error > "attribute is not a field declaration in the same structure as" } */ > + int array_fam[] __attribute__ ((counted_by (count))); /* { dg-error > "attribute is not a field declaration in the same structure as" } */ > +}; > + > +struct pointer_array_2 { > + float count1; > + float count2; > + int *array_2 __attribute__ ((counted_by (count1))); /* { dg-error > "attribute is not a field declaration with an integer type" } */ > + int array_fam[] __attribute__ ((counted_by (count2))); /* { dg-error > "attribute is not a field declaration with an integer type" } */ > +}; > + > +struct pointer_array_3 { > + int count; > + int *array_3 __attribute__ ((counted_by (count))) __attribute__ > ((counted_by (count))); > +}; > + > +struct pointer_array_4 { > + int count1; > + int count2; > + int *array_4 __attribute__ ((counted_by (count1))) __attribute__ > ((counted_by (count2))); /* { dg-error "conflicts with previous declaration" > } */ > + float array_fam[] __attribute__ ((counted_by (count2))) __attribute__ > ((counted_by (count1))); /* { dg-error "conflicts with previous declaration" > } */ > +}; > + > +struct pointer_array_5 { > + _Bool count; > + int *array_5 __attribute__ ((counted_by (count))); > +}; > + > +enum week {Mon, Tue, Wed}; > +struct pointer_array_6 { > + enum week days; > + int *array_6 __attribute__ ((counted_by (days))); > +}; > + > +struct pointer_array_7 { > + int count; > + void *array_7 __attribute__ ((counted_by (count))); /* { dg-error > "attribute is not allowed for a pointer field with void pointee type" } */ > +}; > + > +struct mixed_array { > + int count1; > + float *array_1 __attribute__ ((counted_by (count1))); > + float *array_2 __attribute__ ((counted_by (count1))); > + int count2; > + long *array_3 __attribute__ ((counted_by (count2))); > + long array_4[] __attribute__ ((counted_by (count2))); > +}; > + > +struct mixed_array_2 { > + float *array_1 __attribute__ ((counted_by (count1))); > + int count1; > + float *array_2 __attribute__ ((counted_by (count1))); > + long *array_3 __attribute__ ((counted_by (count2))); > + int count2; > + long array_4[] __attribute__ ((counted_by (count2))); > +}; > -- > 2.31.1 >