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                    |  15 ++-
 gcc/c/c-decl.cc                              |  91 +++++++------
 gcc/doc/extend.texi                          |  37 +++++-
 gcc/testsuite/gcc.dg/flex-array-counted-by.c |   2 +-
 gcc/testsuite/gcc.dg/pointer-counted-by-2.c  |   8 ++
 gcc/testsuite/gcc.dg/pointer-counted-by-3.c  | 127 +++++++++++++++++++
 gcc/testsuite/gcc.dg/pointer-counted-by.c    |  70 ++++++++++
 7 files changed, 298 insertions(+), 52 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 eb76430dd07..6dd23db4f9d 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -2906,16 +2906,18 @@ 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"
@@ -2930,7 +2932,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 f60b2a54a17..2c242ce8593 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 1e1b4cc837d..dddc8cbca9d 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7965,9 +7965,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.
@@ -7988,8 +7990,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
@@ -8000,7 +8016,7 @@ negative integer value, the compiler treats the value as 
zero.
 
 An explicit @code{counted_by} annotation defines a relationship between
 two objects, @code{p->array} and @code{p->count}, and there are the
-following requirementthat on the relationship between this pair:
+following requirements on the relationship between this pair:
 
 @itemize @bullet
 @item
@@ -8013,6 +8029,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 user's responsibility to make sure the above requirements to
 be kept all the time.  Otherwise the compiler reports warnings,
 at the same time, the results of the array bound sanitizer and the
@@ -8034,6 +8057,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..bd86d37b628
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pointer-counted-by-2.c
@@ -0,0 +1,8 @@
+/* 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)));
+};
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..45a83612c73
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pointer-counted-by.c
@@ -0,0 +1,70 @@
+/* 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 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