> On Sep 11, 2024, at 18:16, Bill Wendling <isanb...@gmail.com> wrote:
> 
> On Wed, Sep 11, 2024 at 2:13 PM Qing Zhao <qing.z...@oracle.com> wrote:
>> 
>> compared to the 4th version, the changes are (address Jacub's concerns):
>> 
>> 1. change the global "in_builtin_counted_by_ref" from a boolean to an int;
>> 2. delete the label for the error handling code, and decress the global
>>   "in_builtin_counted_by_ref" before each break;
>> 
>> the 4th version compared to the 3rd version, the only change is the
>> size calculation in the testing case.
>> 
>> The 3rd version compared to the 2nd version, the major change is:
>> the update in testing cases per Martin's suggestions.
>> 
>> when the 2nd version is compared to the first version, the major changes are:
>> 
>> 1. change the name of the builtin from __builtin_get_counted_by to
>> __builtin_counted_by_ref in order to reflect the fact that the returned
>> value of it is a reference to the object.
>> 
>> 2. make typeof(__builtin_counted_by_ref) working.
>> 
>> 3. update the testing case to use the new builtin inside _Generic.
>> 
>> bootstrapped and regress tested on both X86 and aarch64. no issue.
>> 
>> Okay for the trunk?
>> 
>> thanks.
>> 
>> Qing.
>> 
>> ==============================================
>> 
>> With the addition of the 'counted_by' attribute and its wide roll-out
>> within the Linux kernel, a use case has been found that would be very
>> nice to have for object allocators: being able to set the counted_by
>> counter variable without knowing its name.
>> 
>> For example, given:
>> 
>>  struct foo {
>>    ...
>>    int counter;
>>    ...
>>    struct bar array[] __attribute__((counted_by (counter)));
>>  } *p;
>> 
>> The existing Linux object allocators are roughly:
>> 
>>  #define MAX(A, B) (A > B) ? (A) : (B)
>>  #define alloc(P, FAM, COUNT) ({ \
>>    __auto_type __p = &(P); \
>>    size_t __size = MAX (sizeof(*P),
>>                         __builtin_offsetof (__typeof(*P), FAM)
>>                         + sizeof (*(P->FAM)) * COUNT); \
>>    *__p = kmalloc(__size); \
>>  })
>> 
>> Right now, any addition of a counted_by annotation must also
>> include an open-coded assignment of the counter variable after
>> the allocation:
>> 
>>  p = alloc(p, array, how_many);
>>  p->counter = how_many;
>> 
>> In order to avoid the tedious and error-prone work of manually adding
>> the open-coded counted-by intializations everywhere in the Linux
>> kernel, a new GCC builtin __builtin_counted_by_ref will be very useful
>> to be added to help the adoption of the counted-by attribute.
>> 
>> -- Built-in Function: TYPE __builtin_counted_by_ref (PTR)
>>     The built-in function '__builtin_counted_by_ref' checks whether the
>>     array object pointed by the pointer PTR has another object
>>     associated with it that represents the number of elements in the
>>     array object through the 'counted_by' attribute (i.e.  the
>>     counted-by object).  If so, returns a pointer to the corresponding
>>     counted-by object.  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 PTR must be a pointer to an array.  The TYPE of the
>>     returned value must be a pointer type pointing to the corresponding
>>     type of the counted-by object or VOID pointer type in case of a
>>     NULL pointer being returned.
>> 
>> With this new builtin, the central allocator could be updated to:
>> 
>>  #define MAX(A, B) (A > B) ? (A) : (B)
>>  #define alloc(P, FAM, COUNT) ({ \
>>    __auto_type __p = &(P); \
>>    __auto_type __c = (COUNT); \
>>    size_t __size = MAX (sizeof (*(*__p)),\
>>                         __builtin_offsetof (__typeof(*(*__p)),FAM) \
>>                         + sizeof (*((*__p)->FAM)) * __c); \
>>    if ((*__p = kmalloc(__size))) { \
>>      __auto_type ret = __builtin_counted_by_ref((*__p)->FAM); \
>>      *_Generic(ret, void *: &(size_t){0}, default: ret) = __c; \
>>    } \
>>  })
>> 
>> And then structs can gain the counted_by attribute without needing
>> additional open-coded counter assignments for each struct, and
>> unannotated structs could still use the same allocator.
>> 
>>        PR c/116016
>> 
>> gcc/c-family/ChangeLog:
>> 
>>        * c-common.cc: Add new __builtin_counted_by_ref.
>>        * c-common.h (enum rid): Add RID_BUILTIN_COUNTED_BY_REF.
>> 
>> gcc/c/ChangeLog:
>> 
>>        * c-decl.cc (names_builtin_p): Add RID_BUILTIN_COUNTED_BY_REF.
>>        * c-parser.cc (has_counted_by_object): New routine.
>>        (get_counted_by_ref): New routine.
>>        (c_parser_postfix_expression): Handle New RID_BUILTIN_COUNTED_BY_REF.
>>        * c-tree.h: New global in_builtin_counted_by_ref.
>>        * c-typeck.cc (build_component_ref): Enable generating
>>        .ACCESS_WITH_SIZE inside typeof when inside builtin_counted_by_ref.
>> 
>> gcc/ChangeLog:
>> 
>>        * doc/extend.texi: Add documentation for __builtin_counted_by_ref.
>> 
>> gcc/testsuite/ChangeLog:
>> 
>>        * gcc.dg/builtin-counted-by-ref-1.c: New test.
>>        * gcc.dg/builtin-counted-by-ref.c: New test.
>> ---
>> gcc/c-family/c-common.cc                      |  1 +
>> gcc/c-family/c-common.h                       |  1 +
>> gcc/c/c-decl.cc                               |  1 +
>> gcc/c/c-parser.cc                             | 78 +++++++++++++++
>> gcc/c/c-tree.h                                |  1 +
>> gcc/c/c-typeck.cc                             |  7 +-
>> gcc/doc/extend.texi                           | 55 +++++++++++
>> .../gcc.dg/builtin-counted-by-ref-1.c         | 97 +++++++++++++++++++
>> gcc/testsuite/gcc.dg/builtin-counted-by-ref.c | 61 ++++++++++++
>> 9 files changed, 301 insertions(+), 1 deletion(-)
>> create mode 100644 gcc/testsuite/gcc.dg/builtin-counted-by-ref-1.c
>> create mode 100644 gcc/testsuite/gcc.dg/builtin-counted-by-ref.c
>> 
>> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
>> index e7e371fd26f..15b90bae8b5 100644
>> --- a/gcc/c-family/c-common.cc
>> +++ b/gcc/c-family/c-common.cc
>> @@ -430,6 +430,7 @@ const struct c_common_resword c_common_reswords[] =
>>   { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY },
>>   { "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY },
>>   { "__builtin_convertvector", RID_BUILTIN_CONVERTVECTOR, 0 },
>> +  { "__builtin_counted_by_ref", RID_BUILTIN_COUNTED_BY_REF, D_CONLY },
>>   { "__builtin_has_attribute", RID_BUILTIN_HAS_ATTRIBUTE, 0 },
>>   { "__builtin_launder", RID_BUILTIN_LAUNDER, D_CXXONLY },
>>   { "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 },
>> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
>> index 027f077d51b..4400d2c5d43 100644
>> --- a/gcc/c-family/c-common.h
>> +++ b/gcc/c-family/c-common.h
>> @@ -110,6 +110,7 @@ enum rid
>>   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,       
>> RID_BUILTIN_SHUFFLE,
>>   RID_BUILTIN_SHUFFLEVECTOR,   RID_BUILTIN_CONVERTVECTOR,  
>> RID_BUILTIN_TGMATH,
>>   RID_BUILTIN_HAS_ATTRIBUTE,   RID_BUILTIN_ASSOC_BARRIER,  RID_BUILTIN_STDC,
>> +  RID_BUILTIN_COUNTED_BY_REF,
>>   RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
>> 
>>   /* TS 18661-3 keywords, in the same sequence as the TI_* values.  */
>> diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
>> index aa7f69d1b7b..1145dde9bb1 100644
>> --- a/gcc/c/c-decl.cc
>> +++ b/gcc/c/c-decl.cc
>> @@ -11788,6 +11788,7 @@ names_builtin_p (const char *name)
>>     case RID_BUILTIN_SHUFFLE:
>>     case RID_BUILTIN_SHUFFLEVECTOR:
>>     case RID_BUILTIN_STDC:
>> +    case RID_BUILTIN_COUNTED_BY_REF:
>>     case RID_CHOOSE_EXPR:
>>     case RID_OFFSETOF:
>>     case RID_TYPES_COMPATIBLE_P:
>> diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
>> index aff5af17430..91bd91f4be1 100644
>> --- a/gcc/c/c-parser.cc
>> +++ b/gcc/c/c-parser.cc
>> @@ -10647,6 +10647,35 @@ c_parser_predefined_identifier (c_parser *parser)
>>   return expr;
>> }
>> 
>> +/* Check whether the ARRAY_REF has an counted-by object associated with it
>> +   through the "counted_by" attribute.  */
>> +static bool
>> +has_counted_by_object (tree array_ref)
>> +{
>> +  /* Currently, only when the array_ref is an indirect_ref to a call to the
>> +     .ACCESS_WITH_SIZE, return true.
>> +     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 true;
>> +  return false;
>> +}
>> +
>> +/* Get the reference to the counted-by object associated with the 
>> ARRAY_REF.  */
>> +static tree
>> +get_counted_by_ref (tree array_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.
>> +     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);
>> +  return NULL_TREE;
>> +}
>> +
>> /* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2,
>>    C11 6.5.1-6.5.2).  Compound literals aren't handled here; callers have to
>>    call c_parser_postfix_expression_after_paren_type on encountering them.
>> @@ -11741,6 +11770,55 @@ c_parser_postfix_expression (c_parser *parser)
>>            set_c_expr_source_range (&expr, loc, close_paren_loc);
>>            break;
>>          }
>> +       case RID_BUILTIN_COUNTED_BY_REF:
>> +         {
>> +           vec<c_expr_t, va_gc> *cexpr_list;
>> +           c_expr_t *e_p;
>> +           location_t close_paren_loc;
>> +
>> +           in_builtin_counted_by_ref++;
>> +
>> +           c_parser_consume_token (parser);
>> +           if (!c_parser_get_builtin_args (parser,
>> +                                           "__builtin_counted_by_ref",
>> +                                           &cexpr_list, false,
>> +                                           &close_paren_loc))
>> +             {
>> +               expr.set_error ();
>> +               in_builtin_counted_by_ref--;
>> +               break;
>> +             }
>> +           if (vec_safe_length (cexpr_list) != 1)
>> +             {
>> +               error_at (loc, "wrong number of arguments to "
>> +                              "%<__builtin_counted_by_ref%>");
>> +               expr.set_error ();
>> +               in_builtin_counted_by_ref--;
>> +               break;
>> +             }
>> +
>> +           e_p = &(*cexpr_list)[0];
>> +
>> +           if (TREE_CODE (TREE_TYPE (e_p->value)) != ARRAY_TYPE)
>> +             {
>> +               error_at (loc, "the argument must be an array"
>> +                              "%<__builtin_counted_by_ref%>");
>> +               expr.set_error ();
>> +               in_builtin_counted_by_ref--;
>> +               break;
>> +             }
>> +
>> +           if (has_counted_by_object ((*cexpr_list)[0].value))
>> +             expr.value
>> +               = get_counted_by_ref ((*cexpr_list)[0].value);
>> +           else
>> +             expr.value
>> +               = build_int_cst (build_pointer_type (void_type_node), 0);
>> +
>> +           set_c_expr_source_range (&expr, loc, close_paren_loc);
>> +           in_builtin_counted_by_ref--;
>> +           break;
>> +         }
>>        case RID_BUILTIN_SHUFFLE:
>>          {
>>            vec<c_expr_t, va_gc> *cexpr_list;
>> diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
>> index 57befb94c08..6f46b2ff5a0 100644
>> --- a/gcc/c/c-tree.h
>> +++ b/gcc/c/c-tree.h
>> @@ -737,6 +737,7 @@ extern int c_type_dwarf_attribute (const_tree, int);
>> extern int in_alignof;
>> extern int in_sizeof;
>> extern int in_typeof;
>> +extern int in_builtin_counted_by_ref;
>> extern bool c_in_omp_for;
>> extern bool c_omp_array_section_p;
>> 
>> diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
>> index 58b2724b39e..8cb2cb60f6a 100644
>> --- a/gcc/c/c-typeck.cc
>> +++ b/gcc/c/c-typeck.cc
>> @@ -74,6 +74,9 @@ int in_sizeof;
>> /* The level of nesting inside "typeof".  */
>> int in_typeof;
>> 
>> +/* The level of nesting inside "builtin_counted_by_ref".  */
>> +int in_builtin_counted_by_ref;
>> +
>> /* True when parsing OpenMP loop expressions.  */
>> bool c_in_omp_for;
>> 
>> @@ -2848,7 +2851,9 @@ build_component_ref (location_t loc, tree datum, tree 
>> component,
>>          bool use_datum_quals;
>>          tree counted_by_type = NULL_TREE;
>>          /* Do not handle counted_by when in typeof and alignof operator.  */
>> -         handle_counted_by = handle_counted_by && !in_typeof && !in_alignof;
>> +         handle_counted_by = handle_counted_by
>> +                             && !(in_typeof && !in_builtin_counted_by_ref)
>> +                             && !in_alignof;
>>          tree counted_by_ref = handle_counted_by
>>                                ? build_counted_by_ref (datum, subdatum,
>>                                                        &counted_by_type)
>> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
>> index 2d795ba7e59..268e50677d7 100644
>> --- a/gcc/doc/extend.texi
>> +++ b/gcc/doc/extend.texi
>> @@ -15287,6 +15287,61 @@ initializers of variables usable in constant 
>> expressions.   For more details
>> refer to the latest revision of the C++ standard.
>> @enddefbuiltin
>> 
>> +@defbuiltin{@var{type} __builtin_counted_by_ref (@var{ptr})}
>> +The built-in function @code{__builtin_counted_by_ref} checks whether the 
>> array
>> +object pointed by the pointer @var{ptr} has another object associated with 
>> it
>> +that represents the number of elements in the array object through the
>> +@code{counted_by} attribute (i.e. the counted-by object). If so, returns a
>> +pointer to the corresponding counted-by object.
>> +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 @var{type} of the returned value must be 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.
>> +
> Having the return type default to a VOID pointer restricts it from this use:
> 
>  if (__builtin_counted_by_ref(p->FAM))
>    *__builtin_counted_by_ref(p->FAM) = 42;
> 
> The second line will emit a diagnostic.

We have discussion on this during the 1st version of the patch. at that 
version, the __builtin_counted_by_ref return a size_t * void pointer if no 
counted_by attribute for the above usage, however, Richard pointed out that 
"the above usage is odd for a statically typed languages, on the other hand, 
type selection like generics or __builtin_classify_type instead of overloading 
the value producing builtin might be more fit”.  please see the following for 
more details:

https://gcc.gnu.org/pipermail/gcc-patches/2024-August/660871.html
https://gcc.gnu.org/pipermail/gcc-patches/2024-August/660908.html
https://gcc.gnu.org/pipermail/gcc-patches/2024-August/660995.html

> Is VOID pointer just to make
> using _Generic a bit cleaner? Is that now the prefered way to use this
> builtin?

Yes, I think so. __Generic or __builtin_choose_expr is the preferred way to use 
this builtin. 

Qing


> 
> -bw
> 
>> +For example:
>> +
>> +@smallexample
>> +struct foo1 @{
>> +  int counter;
>> +  struct bar1 array[] __attribute__((counted_by (counter)));
>> +@} *p;
>> +
>> +struct foo2 @{
>> +  int other;
>> +  struct bar2 array[];
>> +@} *q;
>> +@end smallexample
>> +
>> +@noindent
>> +the following call to the built-in
>> +
>> +@smallexample
>> +__builtin_counted_by_ref (p->array)
>> +@end smallexample
>> +
>> +@noindent
>> +returns:
>> +
>> +@smallexample
>> +&p->counter with type @code{int *}.
>> +@end smallexample
>> +
>> +@noindent
>> +However, the following call to the built-in
>> +
>> +@smallexample
>> +__builtin_counted_by_ref (q->array)
>> +@end smallexample
>> +
>> +@noindent
>> +returns a void NULL pointer.
>> +
>> +@enddefbuiltin
>> +
>> @defbuiltin{void __builtin_clear_padding (@var{ptr})}
>> The built-in function @code{__builtin_clear_padding} function clears
>> padding bits inside of the object representation of object pointed by
>> diff --git a/gcc/testsuite/gcc.dg/builtin-counted-by-ref-1.c 
>> b/gcc/testsuite/gcc.dg/builtin-counted-by-ref-1.c
>> new file mode 100644
>> index 00000000000..d055cf1defc
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/builtin-counted-by-ref-1.c
>> @@ -0,0 +1,97 @@
>> +/* Test the code generation for the new __builtin_counted_by_ref.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2" } */
>> +#include <stdio.h>
>> +
>> +struct annotated {
>> +  char b;
>> +  int c[] __attribute ((counted_by (b)));
>> +} *array_annotated;
>> +
>> +struct flex {
>> +  short b;
>> +  int c[];
>> +} *array_flex;
>> +
>> +struct nested_annotated {
>> +  struct {
>> +    union {
>> +      int b;
>> +      float f;
>> +    };
>> +    int n;
>> +  };
>> +  char c[] __attribute__ ((counted_by (b)));
>> +} *array_nested_annotated;
>> +
>> +struct nested_flex {
>> +  struct {
>> +    union {
>> +      unsigned int b;
>> +      float f;
>> +    };
>> +    int n;
>> +  };
>> +  char c[];
>> +} *array_nested_flex;
>> +
>> +#define MAX(A, B) (A > B) ? (A) : (B)
>> +#define MY_ALLOC(P, FAM, COUNT) ({ \
>> +  __auto_type __p = &(P); \
>> +  __auto_type __c = (COUNT); \
>> +  size_t __size = MAX (sizeof (*(*__p)),\
>> +                      __builtin_offsetof (__typeof(*(*__p)),FAM) \
>> +                      + sizeof (*((*__p)->FAM)) * __c); \
>> +  if ((*__p = __builtin_malloc(__size))) { \
>> +    __builtin_memset(*__p, 0, __size); \
>> +    __auto_type ret = __builtin_counted_by_ref((*__p)->FAM); \
>> +    *_Generic(ret, void *: &(size_t){0}, default: ret) = __c; \
>> +    if (sizeof (__builtin_counted_by_ref ((*__p)->FAM)) != sizeof (char *)) 
>> \
>> +      __builtin_abort (); \
>> +  } \
>> +})
>> +
>> +int count;
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +  MY_ALLOC(array_annotated, c, 10);
>> +  if (array_annotated->b != 10)
>> +    __builtin_abort ();
>> +
>> +  MY_ALLOC(array_flex, c, 20);
>> +  if (array_flex->b == 20)
>> +    __builtin_abort ();
>> +
>> +  MY_ALLOC(array_nested_annotated, c, 30);
>> +  if (array_nested_annotated->b != 30)
>> +    __builtin_abort ();
>> +
>> +  MY_ALLOC(array_nested_flex, c, 40);
>> +  if (array_nested_flex->b == 40)
>> +    __builtin_abort ();
>> +
>> +  count = array_annotated->b * 2 + array_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 ();
>> +
>> +  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 ();
>> +
>> +  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
>> new file mode 100644
>> index 00000000000..4aa57ffb916
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/builtin-counted-by-ref.c
>> @@ -0,0 +1,61 @@
>> +/* Testing the correct usage of the new __builtin_counted_by_ref.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O" } */
>> +
>> +#include <stdio.h>
>> +
>> +struct annotated {
>> +  size_t b;
>> +  int other;
>> +  int c[] __attribute ((counted_by (b)));
>> +} *array_annotated;
>> +
>> +struct flex {
>> +  size_t b;
>> +  int other;
>> +  int c[];
>> +} *array_flex;
>> +
>> +#define MAX(A, B) (A > B) ? (A) : (B)
>> +#define MY_ALLOC(P, FAM, COUNT) ({ \
>> +  __auto_type __p = &(P); \
>> +  __auto_type __c = (COUNT); \
>> +  size_t __size = MAX (sizeof (*(*__p)),\
>> +                      __builtin_offsetof (__typeof(*(*__p)),FAM) \
>> +                      + sizeof (*((*__p)->FAM)) * __c); \
>> +  if ((*__p = __builtin_malloc(__size))) { \
>> +    __builtin_memset(*__p, 0, __size); \
>> +    __auto_type ret = __builtin_counted_by_ref((*__p)->FAM); \
>> +    *_Generic(ret, void *: &(size_t){0}, default: ret) = __c; \
>> +    if (sizeof (__builtin_counted_by_ref ((*__p)->FAM)) != 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(array_annotated, c, 10);
>> +  MY_ALLOC(array_flex, c, 20);
>> +  MY_ALLOC(array_annotated, c, c_count);
>> +  MY_ALLOC(array_flex, c, i_count);
>> +  MY_ALLOC(array_annotated, c, l_count);
>> +  MY_ALLOC(array_flex, c, c_count * 3);
>> +  MY_ALLOC(array_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 (array_annotated->c, 10); /* { dg-error "wrong 
>> number of arguments to" } */
>> +  __builtin_counted_by_ref (array_annotated->other); /* { dg-error "the 
>> argument must be an array" } */
>> +  __builtin_counted_by_ref (foo());  /* { dg-error "the argument must be an 
>> array" } */
>> +
>> +  return 0;
>> +}
>> --
>> 2.31.1


Reply via email to