https://gcc.gnu.org/g:25c8599ad467f73953a6c4b838b1122c4803b1a1
commit r16-6585-g25c8599ad467f73953a6c4b838b1122c4803b1a1 Author: Qing Zhao <[email protected]> Date: Thu Jan 8 15:01:04 2026 +0000 __builtin_counted_by_ref should be extended to support pointers after the counted_by attribute is extended to pointers inside structures. gcc/c/ChangeLog: * c-parser.cc (has_counted_by_object): Support pointers. (get_counted_by_ref): Support pointers. (c_parser_postfix_expression): Support pointers. gcc/ChangeLog: * doc/extend.texi: Update doc to support pointers inside structures. gcc/testsuite/ChangeLog: * gcc.dg/builtin-counted-by-ref.c: Update test case. * gcc.dg/builtin-counted-by-ref-2.c: New test. * gcc.dg/builtin-counted-by-ref-3.c: New test. Diff: --- gcc/c/c-parser.cc | 51 ++++++--- gcc/doc/extend.texi | 27 ++++- gcc/testsuite/gcc.dg/builtin-counted-by-ref-2.c | 61 +++++++++++ gcc/testsuite/gcc.dg/builtin-counted-by-ref-3.c | 135 ++++++++++++++++++++++++ gcc/testsuite/gcc.dg/builtin-counted-by-ref.c | 4 +- 5 files changed, 256 insertions(+), 22 deletions(-) diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 0cc8be10eb05..931ae88cd2fb 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -11654,34 +11654,44 @@ c_parser_predefined_identifier (c_parser *parser) return expr; } -/* Check whether the ARRAY_REF has an counted-by object associated with it +/* Check whether the REF has an counted-by object associated with it through the "counted_by" attribute. */ static bool -has_counted_by_object (tree array_ref) +has_counted_by_object (tree ref) { - /* Currently, only when the array_ref is an indirect_ref to a call to the - .ACCESS_WITH_SIZE, return true. + /* Currently, there are two cases are valid: + A. when the ref is an indirect_ref to a call to the + .ACCESS_WITH_SIZE, return true. (this is for FAM) + B. when the ref is a call to .ACCESS_WITH_SIZE, return true. + (this is for pointer field inside a structure) More cases can be included later when the counted_by attribute is extended to other situations. */ - if (TREE_CODE (array_ref) == INDIRECT_REF - && is_access_with_size_p (TREE_OPERAND (array_ref, 0))) + if ((TREE_CODE (ref) == INDIRECT_REF + && is_access_with_size_p (TREE_OPERAND (ref, 0))) + || is_access_with_size_p (ref)) return true; return false; } -/* Get the reference to the counted-by object associated with the ARRAY_REF. */ +/* Get the reference to the counted-by object associated with the REF. */ static tree -get_counted_by_ref (tree array_ref) +get_counted_by_ref (tree ref) { - /* Currently, only when the array_ref is an indirect_ref to a call to the - .ACCESS_WITH_SIZE, get the corresponding counted_by ref. + /* Currently, there are two cases are valid: + A. when the ref is an indirect_ref to a call to the + .ACCESS_WITH_SIZE, return true. (this is for FAM) + B. when the ref is a call to .ACCESS_WITH_SIZE, return true. + (this is for pointer field inside a structure) More cases can be included later when the counted_by attribute is extended to other situations. */ - if (TREE_CODE (array_ref) == INDIRECT_REF - && is_access_with_size_p (TREE_OPERAND (array_ref, 0))) - return CALL_EXPR_ARG (TREE_OPERAND (array_ref, 0), 1); + if (TREE_CODE (ref) == INDIRECT_REF + && is_access_with_size_p (TREE_OPERAND (ref, 0))) + return CALL_EXPR_ARG (TREE_OPERAND (ref, 0), 1); + else if (is_access_with_size_p (ref)) + return CALL_EXPR_ARG (ref, 1); + return NULL_TREE; } @@ -12893,15 +12903,24 @@ c_parser_postfix_expression (c_parser *parser) e_p = &(*cexpr_list)[0]; tree ref = e_p->value; - if (TREE_CODE (TREE_TYPE (ref)) != ARRAY_TYPE) + if (TREE_CODE (TREE_TYPE (ref)) != ARRAY_TYPE + && TREE_CODE (TREE_TYPE (ref)) != POINTER_TYPE) + { + error_at (loc, "the argument to %<__builtin_counted_by_ref%>" + " must be an array or pointer"); + expr.set_error (); + break; + } + + if (TREE_CODE (ref) != COMPONENT_REF) { error_at (loc, "the argument to %<__builtin_counted_by_ref%>" - " must be an array"); + " must be a field of a structure"); expr.set_error (); break; } - /* If the array ref is inside TYPEOF or ALIGNOF, the call to + /* If the ref is inside TYPEOF or ALIGNOF, the call to .ACCESS_WITH_SIZE was not generated by the routine build_component_ref by default, we should generate it here. */ if (TREE_CODE (ref) == COMPONENT_REF) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 3dca144a7520..a5c687f2667e 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -18197,7 +18197,8 @@ If such counted-by object does not exist, returns a null pointer. This built-in function is only available in C for now. -The argument @var{ptr} must be a pointer to an array. +The argument @var{ptr} must be a pointer to an flexible array or a pointer +inside a structure. The @var{type} of the returned value is a pointer type pointing to the corresponding type of the counted-by object or a void pointer type in case of a null pointer being returned. @@ -18211,9 +18212,15 @@ struct foo1 @{ @} *p; struct foo2 @{ + struct bar2 *pointer __attribute__((counted_by (counter2))); + int counter2; +@} *p2; + +struct foo3 @{ int other; - struct bar2 array[]; -@} *q; + struct bar3 array[]; +@} *p3; + @end smallexample @noindent @@ -18230,11 +18237,23 @@ returns: &p->counter with type @code{int *}. @end smallexample +@smallexample +__builtin_counted_by_ref (p2->pointer) +@end smallexample + +@noindent +returns: + +@smallexample +&p2->counter2 with type @code{int *}. +@end smallexample + + @noindent However, the following call to the built-in @smallexample -__builtin_counted_by_ref (q->array) +__builtin_counted_by_ref (p3->array) @end smallexample @noindent diff --git a/gcc/testsuite/gcc.dg/builtin-counted-by-ref-2.c b/gcc/testsuite/gcc.dg/builtin-counted-by-ref-2.c new file mode 100644 index 000000000000..54f2613fa44d --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-counted-by-ref-2.c @@ -0,0 +1,61 @@ +/* Testing the correct usage of the new __builtin_counted_by_ref for + pointers. */ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +#include <stdio.h> + +struct annotated { + size_t b; + int *c __attribute ((counted_by (b))); + int other; +} *p_annotated; + +struct flex { + size_t b; + int *c; + int other; +} *p_flex; + +#define MY_ALLOC(P, PA, COUNT) ({ \ + __auto_type __p = &(P); \ + __auto_type __c = (COUNT); \ + size_t __size_1 = (sizeof (*(*__p))); \ + size_t __size_2 = (sizeof (*((*__p)->PA)) * __c); \ + if ((*__p = __builtin_malloc (__size_1))) { \ + __builtin_memset(*__p, 0, __size_1); \ + (*__p)->PA = __builtin_malloc (__size_2); \ + __auto_type ret = __builtin_counted_by_ref((*__p)->PA); \ + *_Generic(ret, void *: &(size_t){0}, default: ret) = __c; \ + if (sizeof (__builtin_counted_by_ref ((*__p)->PA)) != sizeof (char *)) \ + __builtin_abort (); \ + } \ +}) + +extern char c_count; +extern short s_count; +extern int i_count; +extern long l_count; +extern float f_count; + +extern int * foo (); + +int main(int argc, char *argv[]) +{ + /* The good usages. */ + MY_ALLOC(p_annotated, c, 10); + MY_ALLOC(p_flex, c, 20); + MY_ALLOC(p_annotated, c, c_count); + MY_ALLOC(p_flex, c, i_count); + MY_ALLOC(p_annotated, c, l_count); + MY_ALLOC(p_flex, c, c_count * 3); + MY_ALLOC(p_annotated, c, l_count * i_count); + + /* The bad usages, issue errors. */ + __builtin_counted_by_ref (); /* { dg-error "wrong number of arguments to" } */ + __builtin_counted_by_ref (p_annotated->c, 10); /* { dg-error "wrong number of arguments to" } */ + __builtin_counted_by_ref (p_annotated->other); /* { dg-error "must be an array or pointer" } */ + __builtin_counted_by_ref (foo()); /* { dg-error "must be a field of a structure" } */ + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/builtin-counted-by-ref-3.c b/gcc/testsuite/gcc.dg/builtin-counted-by-ref-3.c new file mode 100644 index 000000000000..6cbb495ffb5a --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-counted-by-ref-3.c @@ -0,0 +1,135 @@ +/* Test the code generation for the new __builtin_counted_by_ref + for pointers. */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ +#include <stdio.h> + +struct annotated { + int *c __attribute ((counted_by (b))); + char b; +} *p_annotated; + +struct flex { + int *c; + short b; +} *p_flex; + +struct nested_annotated { + struct { + union { + int b; + float f; + }; + int n; + }; + char *c __attribute__ ((counted_by (b))); +} *p_nested_annotated; + +struct nested_flex { + struct { + union { + unsigned int b; + float f; + }; + int n; + }; + char *c; +} *p_nested_flex; + +#define MY_ALLOC(P, PA, COUNT) ({ \ + __auto_type __p = &(P); \ + __auto_type __c = (COUNT); \ + size_t __size_1 = (sizeof (*(*__p))); \ + size_t __size_2 = (sizeof (*((*__p)->PA)) * __c); \ + if ((*__p = __builtin_malloc (__size_1))) { \ + __builtin_memset(*__p, 0, __size_1); \ + (*__p)->PA = __builtin_malloc (__size_2); \ + __auto_type ret = __builtin_counted_by_ref((*__p)->PA); \ + *_Generic(ret, void *: &(size_t){0}, default: ret) = __c; \ + if (sizeof (__builtin_counted_by_ref ((*__p)->PA)) != sizeof (char *)) \ + __builtin_abort (); \ + } \ +}) + +int count; + +int main(int argc, char *argv[]) +{ + MY_ALLOC(p_annotated, c, 10); + if (p_annotated->b != 10) + __builtin_abort (); + if (__alignof (*__builtin_counted_by_ref (p_annotated->c)) + != __alignof (p_annotated->b)) + __builtin_abort (); + if (!__builtin_types_compatible_p + (__typeof (*__builtin_counted_by_ref (p_annotated->c)), + __typeof (p_annotated->b))) + __builtin_abort (); + if (!__builtin_types_compatible_p + (__typeof (char[__builtin_counted_by_ref (p_annotated->c) + == &p_annotated->b ? 1 : 10]), + __typeof (char[1]))) + __builtin_abort (); + + MY_ALLOC(p_flex, c, 20); + if (p_flex->b == 20) + __builtin_abort (); + if (!__builtin_types_compatible_p + (__typeof (char[__builtin_counted_by_ref (p_flex->c) + == &p_flex->b ? 1 : 10]), + __typeof (char[10]))) + __builtin_abort (); + + MY_ALLOC(p_nested_annotated, c, 30); + if (p_nested_annotated->b != 30) + __builtin_abort (); + if (__alignof (*__builtin_counted_by_ref (p_nested_annotated->c)) + != __alignof (p_nested_annotated->b)) + __builtin_abort (); + if (!__builtin_types_compatible_p + (__typeof (*__builtin_counted_by_ref (p_nested_annotated->c)), + __typeof (p_nested_annotated->b))) + __builtin_abort (); + + MY_ALLOC(p_nested_flex, c, 40); + if (p_nested_flex->b == 40) + __builtin_abort (); + + count = p_annotated->b * 2 + p_nested_annotated->b * 3; + struct annotated * annotated_p; + struct flex * flex_p; + struct nested_annotated * nested_annotated_p; + struct nested_flex * nested_flex_p; + + MY_ALLOC(annotated_p, c, count); + if (annotated_p->b != count) + __builtin_abort (); + if (__alignof (*__builtin_counted_by_ref (annotated_p->c)) + != __alignof (annotated_p->b)) + __builtin_abort (); + if (!__builtin_types_compatible_p + (__typeof (*__builtin_counted_by_ref (annotated_p->c)), + __typeof (annotated_p->b))) + __builtin_abort (); + + MY_ALLOC(flex_p, c, count * 2); + if (flex_p->b == count * 2) + __builtin_abort (); + + MY_ALLOC(nested_annotated_p, c, count * 3); + if (nested_annotated_p->b != count * 3) + __builtin_abort (); + if (__alignof (*__builtin_counted_by_ref (nested_annotated_p->c)) + != __alignof (nested_annotated_p->b)) + __builtin_abort (); + if (!__builtin_types_compatible_p + (__typeof (*__builtin_counted_by_ref (nested_annotated_p->c)), + __typeof (nested_annotated_p->b))) + __builtin_abort (); + + MY_ALLOC(nested_flex_p, c, count * 4); + if (nested_flex_p->b == count * 4) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/builtin-counted-by-ref.c b/gcc/testsuite/gcc.dg/builtin-counted-by-ref.c index 33f88e23913b..dab306ea5558 100644 --- a/gcc/testsuite/gcc.dg/builtin-counted-by-ref.c +++ b/gcc/testsuite/gcc.dg/builtin-counted-by-ref.c @@ -54,8 +54,8 @@ int main(int argc, char *argv[]) /* The bad usages, issue errors. */ __builtin_counted_by_ref (); /* { dg-error "wrong number of arguments to" } */ __builtin_counted_by_ref (array_annotated->c, 10); /* { dg-error "wrong number of arguments to" } */ - __builtin_counted_by_ref (array_annotated->other); /* { dg-error "must be an array" } */ - __builtin_counted_by_ref (foo()); /* { dg-error "must be an array" } */ + __builtin_counted_by_ref (array_annotated->other); /* { dg-error "must be an array or pointer" } */ + __builtin_counted_by_ref (foo()); /* { dg-error "must be a field of a structure" } */ return 0; }
