Ping on this patch. thanks.
Qing > On Dec 16, 2025, at 10:19, Qing Zhao <[email protected]> wrote: > > __builtin_bounted_by_ref should be extended to support pointers inside > structures after the counted_by attribute is extended to pointers inside > structures. > > The patch has been bootstrapped and regression tested on both X86 and aarch64. > > Okay for committing? > > thanks. > > Qing > > ===================================== > 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. > --- > gcc/c/c-parser.cc | 51 ++++--- > gcc/doc/extend.texi | 27 +++- > .../gcc.dg/builtin-counted-by-ref-2.c | 61 ++++++++ > .../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(-) > create mode 100644 gcc/testsuite/gcc.dg/builtin-counted-by-ref-2.c > create mode 100644 gcc/testsuite/gcc.dg/builtin-counted-by-ref-3.c > > diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc > index abe024c84b3..77dfc349991 100644 > --- a/gcc/c/c-parser.cc > +++ b/gcc/c/c-parser.cc > @@ -11653,34 +11653,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; > } > > @@ -12892,15 +12902,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 0536ca7ae93..fe8134cc05b 100644 > --- a/gcc/doc/extend.texi > +++ b/gcc/doc/extend.texi > @@ -18185,7 +18185,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. > @@ -18199,9 +18200,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 > @@ -18218,11 +18225,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 00000000000..54f2613fa44 > --- /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 00000000000..6cbb495ffb5 > --- /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 33f88e23913..dab306ea555 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; > } > -- > 2.31.1 >
