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
> 

Reply via email to