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                          |  35 ++++-
 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    |  70 ++++++++++
 7 files changed, 299 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..51d42999578 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 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..1f73a9430a7 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
@@ -7164,6 +7180,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 +7208,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..33007803d50
--- /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..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