" 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)
{
*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));
}
}
-/* 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));
+ }
+ }
}
}
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.
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,
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;
}
/* 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:
*/
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,
}
/* 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
(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
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);
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;
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,
@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.
@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
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:
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
@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})
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 {
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+};
--- /dev/null
+ /* 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" } */
+}
--- /dev/null
+/* 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)));
+};