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
> 

Reply via email to