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.
        * c-typeck.cc (build_counted_by_ref): Handle pointers with counted_by.
        Add one more argument, issue error when the pointee type is a structure
        or union including a flexible array member.
        (build_access_with_size_for_counted_by): Handle pointers with 
counted_by.
        (handle_counted_by_for_component_ref): Call build_counted_by_ref
        with the new prototype.

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-1.c: New 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                    |  44 ++++++-
 gcc/c/c-decl.cc                              |  91 +++++++------
 gcc/c/c-typeck.cc                            |  60 ++++++---
 gcc/doc/extend.texi                          |  41 +++++-
 gcc/testsuite/gcc.dg/flex-array-counted-by.c |   2 +-
 gcc/testsuite/gcc.dg/pointer-counted-by-1.c  |  34 +++++
 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    | 111 ++++++++++++++++
 9 files changed, 450 insertions(+), 70 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pointer-counted-by-1.c
 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..a276e5c1f1f 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -2906,22 +2906,53 @@ 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 a 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 to void type.  */
+  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 to void",
+               name);
+      *no_add_attrs = true;
+    }
+  /* This attribute cannot be applied to a pointer to function type.  */
+  else if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE
+          && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == FUNCTION_TYPE)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+               "%qE attribute is not allowed for a pointer to"
+               " function", name);
+      *no_add_attrs = true;
+    }
+  /* This attribute cannot be applied to a pointer to structure or union
+     with flexible array member.  */
+  else if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE
+          && RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_TYPE (decl)))
+          && TYPE_INCLUDES_FLEXARRAY (TREE_TYPE (TREE_TYPE (decl))))
+    {
+       error_at (DECL_SOURCE_LOCATION (decl),
+                 "%qE attribute is not allowed for a pointer to"
+                 " structure or union with flexible array member", name);
+       *no_add_attrs = true;
+    }
   /* The argument should be an identifier.  */
   else if (TREE_CODE (argval) != IDENTIFIER_NODE)
     {
@@ -2930,7 +2961,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 8bbd6ebc66a..7e1c197a7ed 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9432,56 +9432,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));
+           }
+       }
     }
 }
 
@@ -9556,7 +9562,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.
@@ -9637,9 +9643,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,
@@ -9938,8 +9951,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/c/c-typeck.cc b/gcc/c/c-typeck.cc
index e24629be918..794810640e8 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -2922,8 +2922,8 @@ should_suggest_deref_p (tree datum_type)
 
 /* For a SUBDATUM field of a structure or union DATUM, generate a REF to
    the object that represents its counted_by per the attribute counted_by
-   attached to this field if it's a flexible array member field, otherwise
-   return NULL_TREE.
+   attached to this field if it's a flexible array member or a pointer
+   field, otherwise return NULL_TREE.
    Set COUNTED_BY_TYPE to the TYPE of the counted_by field.
    For example, if:
 
@@ -2941,18 +2941,34 @@ should_suggest_deref_p (tree datum_type)
 
 */
 static tree
-build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type)
+build_counted_by_ref (location_t loc, tree datum, tree subdatum,
+                     tree *counted_by_type)
 {
   tree type = TREE_TYPE (datum);
-  if (!c_flexible_array_member_type_p (TREE_TYPE (subdatum)))
+  tree sub_type = TREE_TYPE (subdatum);
+  if (!c_flexible_array_member_type_p (sub_type)
+      && TREE_CODE (sub_type) != POINTER_TYPE)
     return NULL_TREE;
 
+  tree element_type = TREE_TYPE (sub_type);
+
   tree attr_counted_by = lookup_attribute ("counted_by",
                                           DECL_ATTRIBUTES (subdatum));
   tree counted_by_ref = NULL_TREE;
   *counted_by_type = NULL_TREE;
   if (attr_counted_by)
     {
+      /* Issue error when the element_type is a structure or
+        union including a flexible array member.  */
+      if (RECORD_OR_UNION_TYPE_P (element_type)
+         && TYPE_INCLUDES_FLEXARRAY (element_type))
+       {
+         error_at (loc,
+                   "%<counted_by%> attribute is not allowed for a pointer to"
+                   " structure or union with flexible array member");
+         return error_mark_node;
+       }
+
       tree field_id = TREE_VALUE (TREE_VALUE (attr_counted_by));
       counted_by_ref
        = build_component_ref (UNKNOWN_LOCATION,
@@ -2975,8 +2991,11 @@ build_counted_by_ref (tree datum, tree subdatum, tree 
*counted_by_type)
 }
 
 /* Given a COMPONENT_REF REF with the location LOC, the corresponding
-   COUNTED_BY_REF, and the COUNTED_BY_TYPE, generate an INDIRECT_REF
-   to a call to the internal function .ACCESS_WITH_SIZE.
+   COUNTED_BY_REF, and the COUNTED_BY_TYPE, generate the corresponding
+   call to the internal function .ACCESS_WITH_SIZE.
+
+   Generate an INDIRECT_REF to a call to the internal function
+   .ACCESS_WITH_SIZE.
 
    REF
 
@@ -2986,17 +3005,15 @@ build_counted_by_ref (tree datum, tree subdatum, tree 
*counted_by_type)
                        (TYPE_OF_ARRAY *)0))
 
    NOTE: The return type of this function is the POINTER type pointing
-   to the original flexible array type.
-   Then the type of the INDIRECT_REF is the original flexible array type.
-
-   The type of the first argument of this function is a POINTER type
-   to the original flexible array type.
+   to the original flexible array type or the original pointer type.
+   Then the type of the INDIRECT_REF is the original flexible array type
+   or the original pointer type.
 
    The 4th argument of the call is a constant 0 with the TYPE of the
    object pointed by COUNTED_BY_REF.
 
-   The 6th argument of the call is a constant 0 with the pointer TYPE
-   to the original flexible array type.
+   The 6th argument of the call is a constant 0 of the same TYPE as
+   the return type of the call.
 
   */
 static tree
@@ -3004,11 +3021,16 @@ build_access_with_size_for_counted_by (location_t loc, 
tree ref,
                                       tree counted_by_ref,
                                       tree counted_by_type)
 {
-  gcc_assert (c_flexible_array_member_type_p (TREE_TYPE (ref)));
-  /* The result type of the call is a pointer to the flexible array type.  */
+  gcc_assert (c_flexible_array_member_type_p (TREE_TYPE (ref))
+             || TREE_CODE (TREE_TYPE (ref)) == POINTER_TYPE);
+  bool is_fam = c_flexible_array_member_type_p (TREE_TYPE (ref));
+  tree first_param = is_fam ? array_to_pointer_conversion (loc, ref)
+                    : build_unary_op (loc, ADDR_EXPR, ref, false);
+
+  /* The result type of the call is a pointer to the original type
+     of the ref.  */
   tree result_type = c_build_pointer_type (TREE_TYPE (ref));
-  tree first_param
-    = c_fully_fold (array_to_pointer_conversion (loc, ref), false, NULL);
+  first_param = c_fully_fold (first_param, false, NULL);
   tree second_param
     = c_fully_fold (counted_by_ref, false, NULL);
 
@@ -3021,7 +3043,7 @@ build_access_with_size_for_counted_by (location_t loc, 
tree ref,
                                    build_int_cst (counted_by_type, 0),
                                    build_int_cst (integer_type_node, -1),
                                    build_int_cst (result_type, 0));
-  /* Wrap the call with an INDIRECT_REF with the flexible array type.  */
+  /* Wrap the call with an INDIRECT_REF with the original type of the ref.  */
   call = build1 (INDIRECT_REF, TREE_TYPE (ref), call);
   SET_EXPR_LOCATION (call, loc);
   return call;
@@ -3039,7 +3061,7 @@ handle_counted_by_for_component_ref (location_t loc, tree 
ref)
   tree datum = TREE_OPERAND (ref, 0);
   tree subdatum = TREE_OPERAND (ref, 1);
   tree counted_by_type = NULL_TREE;
-  tree counted_by_ref = build_counted_by_ref (datum, subdatum,
+  tree counted_by_ref = build_counted_by_ref (loc, datum, subdatum,
                                              &counted_by_type);
   if (counted_by_ref)
     ref = build_access_with_size_for_counted_by (loc, ref,
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index e4f3cc2ad09..dcbf0af3ecf 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7105,9 +7105,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.
@@ -7128,8 +7130,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
@@ -7138,6 +7154,12 @@ 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 to @code{void},
+a pointer to function, or a pointer to a structure or union that includes
+a flexible array member.  However, it is allowed for a pointer to
+non-void incomplete structure or union types, as long as the type could
+be completed before the first reference to the pointer.
+
 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:
@@ -7153,6 +7175,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
@@ -7174,6 +7203,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-1.c 
b/gcc/testsuite/gcc.dg/pointer-counted-by-1.c
new file mode 100644
index 00000000000..395af3481b2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pointer-counted-by-1.c
@@ -0,0 +1,34 @@
+/* More testing the correct usage of attribute counted_by for pointer field.  
*/
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+typedef struct item1 Item1;
+typedef union item2 Item2;
+
+struct pointer_array {
+  int count1;
+  Item1 *array_1 __attribute__ ((counted_by (count1))); 
+  Item2 *array_2 __attribute__ ((counted_by (count2))); 
+  int count2;
+} *pointer_data; 
+
+struct item1 {
+  int a;
+  float b[];
+};
+
+union item2 {
+  int c;
+  float d[];
+};
+
+void foo ()
+{
+  pointer_data 
+    = (struct pointer_array *) __builtin_malloc (sizeof (struct 
pointer_array));
+  pointer_data->array_1 /* { dg-error "attribute is not allowed for a pointer 
to structure or union with flexible array member" } */ 
+    = (Item1 *) __builtin_malloc (sizeof (Item1) + 3 * sizeof (float));
+  pointer_data->array_2 /* { dg-error "attribute is not allowed for a pointer 
to structure or union with flexible array member" } */
+    = (Item2 *) __builtin_malloc (sizeof (Item2) + 3 * sizeof (float));
+  return;
+}
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..0f18828ac11
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pointer-counted-by.c
@@ -0,0 +1,111 @@
+/* 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 "-O0" } */
+
+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 to void" } */
+}; 
+
+struct pointer_array_8 {
+  int count;
+  int (*fpr)(int,int) __attribute__ ((counted_by (count))); /* { dg-error 
"attribute is not allowed for a pointer to function" } */
+}; 
+
+struct item1 {
+  int a;
+  float b;
+};
+
+union item2 {
+  char *a;
+  int *b; 
+};
+
+typedef struct item3 Item3;
+typedef union item4 Item4;
+
+struct item5 {
+  int a;
+  float b[];
+};
+
+/* Incomplete structure and union are allowed.  */
+struct pointer_array_9 {
+  int count1;
+  int count2;
+  int count3;
+  struct item1 *array_1 __attribute__ ((counted_by (count1)));
+  union item2 *array_2 __attribute__ ((counted_by (count2)));
+  Item3 *array_3 __attribute__ ((counted_by (count3))); 
+  Item4 *array_4 __attribute__ ((counted_by (count4))); 
+  int count4;
+  int count5;
+  /* structure with flexible array member is not allowed.  */
+  struct item5 *array_5 __attribute__ ((counted_by (count5))); /* { dg-error 
"attribute is not allowed for a pointer to structure or union with flexible 
array member" } */
+}; 
+
+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