And Convert a pointer reference with counted_by attribute to
.ACCESS_WITH_SIZE.
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..967e0323c88 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 @code{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