> On Aug 21, 2024, at 04:44, Richard Biener <richard.guent...@gmail.com> wrote:
> 
> On Tue, Aug 20, 2024 at 3:41 PM Qing Zhao <qing.z...@oracle.com> wrote:
>> 
>> 
>> 
>>> On Aug 20, 2024, at 05:58, Richard Biener <richard.guent...@gmail.com> 
>>> wrote:
>>> 
>>> On Tue, Aug 13, 2024 at 5:34 PM Qing Zhao <qing.z...@oracle.com> wrote:
>>>> 
>>>> 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 alloc(P, FAM, COUNT) ({ \
>>>>   size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \
>>>>   kmalloc(__size, GFP); \
>>>> })
>>>> 
>>>> 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_get_counted_by will be very useful
>>>> to be added to help the adoption of the counted-by attribute.
>>>> 
>>>> -- Built-in Function: TYPE __builtin_get_counted_by (PTR)
>>>>    The built-in function '__builtin_get_counted_by' 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 a pointer type pointing to the
>>>>    SIZE_T in case of a NULL pointer being returned.
>>>> 
>>>> With this new builtin, the central allocator could be updated to:
>>>> 
>>>> #define alloc(P, FAM, COUNT) ({ \
>>>>   typeof(P) __p; \
>>>>   size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \
>>>>   __p = kmalloc(__size, GFP); \
>>>>   if (__builtin_get_counted_by (__p->FAM)) \
>>>>     *(__builtin_get_counted_by(__p->FAM)) = COUNT; \
>>>>   __p; \
>>>> })
>>>> 
>>>> 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.
>>> 
>>> Did you consider a __builtin_set_counted_by (PTR, VALUE)?
>> 
>> Yes, that’s the initial request from Kees. -)
>> 
>> The title of PR116016 is: add __builtin_set_counted_by(P->FAM, COUNT) or 
>> equivalent
>> 
>> After extensive discussion (Martin Uecker raised the initial idea in 
>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116016#c24, more discussions 
>> followed, till comments #31). we decided to provide 
>> __builtin_get_counted_by(PTR) instead of __builtin_set_counted_by(PTR, 
>> VALUE) due to the following two reasons:
>> 
>> 1. __builtin_get_counted_by should be enough to provide the functionality, 
>> and even simpler;
>> 2. More flexible to be used by the programmer to be able to both WRITE and 
>> READ the counted-by field.
>> 
>> 
>> 
>>> 
>>> Note that __builtin_get_counted_by to me suggests it returns the
>>> value and not a pointer to the value.
>> 
>> The syntax of __builtin_get_counted_by is:
>> 
>> TYPE __builtin_get_counted_by (PTR)
>> 
>> The returned value is:
>> 
>> 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 a pointer type pointing to the
>>    SIZE_T in case of a NULL pointer being returned.
>> 
>> 
>>> A more proper language extension might involve a keyword
>>> like __real, so __counted_by X would produce an lvalue, selecting
>>> the counted-by member.
>> 
>> Yes, if the returned value could be a LVALUE instead of a Pointer, that’s 
>> even simpler and cleaner.
>> However, then as you mentioned below, another builtin 
>> “__builtin_has_attribute(PTR, counted_by)” need
>> to be queried first to make sure the counted_by field exists.
>> 
>> We have discussed this approach, and I preferred this approach too.
>> 
>> However, the main reason we gave up on that direction is:
>> 
>> There is NO __builtin_has_attribute (PTR, counted_by) been supported by 
>> CLANG, and not sure how difficult for CLANG to add this new builtin.
>> 
>> In order to provide consistent interface to Linux kernel from both CLANG and 
>> GCC,  I finally decided to provide the current interface in order to be 
>> consistent with CLANG.
>> 
>> Bill, could you please provide a little bit more info on the possibility of 
>> a  new builtin __builtin_has_attribute() in CLANG?
>> 
>>> You'd need another way to query whether
>>> 'X' has a counted-by member - the apparent runtime test in your
>>> example is odd for a statically typed language, type selection
>>> like with generics
>> 
>> Could you please explain this a little bit more? (Not quite understood, a 
>> small example will be better, -:) thanks a lot.
>>> or __builtin_classify_type instead of overloading
>>> the value producing builtin might be more fit here?
>> 
>> You mean the following lines from the testing case:
> 
> yes
> 
>> +  if (__builtin_get_counted_by (__p->FAM)) \
>> +  *(__builtin_get_counted_by(__p->FAM)) = COUNT; \
>> 
>> How to improve it? (Thanks a lot for your suggestion).
> 
> There's lack of syntactic guarantee that __builtin_get_counted_by (...) != 0 
> is
> a constant expression.  __builtin_set_counted_by (...) would avoid this
> when it would be documented to expand to nothing for a type without a 
> counted_by
> member.  Writing
> 
> size_t fake;
> __builtin_choose_expr (__builtin_get_counted_by (__p-->FAM) != 0,
> 
> *(__builtin_get_counted_by(__p->FAM)), __fake) = COUNT;
> 
> would ensure this but of course requiring the __fake lvalue is ugly, too.

Yes, you are right. When I wrote the testing case, I felt wield too. (:-

And another issue with the returned value of __builtin_get_counted_by(PTR) is, 
since it returns a pointer, the TYPE of the pointee matters, especially when 
returns a NULL pointer, I used a pointer type pointing to the size_t in case of 
a NULL pointer being returned to avoid some strict-aliasing issue. please see 
PR116316, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116316) for details. 

I do feel that the approach __builtin_get_counted_by is not very good. 
Maybe it’s better to provide 
A. __builtin_set_counted_by 
or
B. The unary operator __counted_by(PTR) to return a Lvalue, in this case, we 
need a __builtin_has_attribute first to check whether PTR has the counted_by 
attribute first.

Any suggestion?

thanks.

Qing

> Richard.
> 
>> 
>> Qing
>> 
>>> 
>>> No objection to the patch but I wanted to share my thoughts here.
>>> 
>>> Richard.
>>> 
>>>> Bootstrapped and regression tested on both X86 and aarch64, no issue.
>>>> 
>>>> Okay for trunk?
>>>> 
>>>> thanks.
>>>> 
>>>> Qing.
>>>> 
>>>> 
>>>>       PR c/116016
>>>> 
>>>> gcc/c-family/ChangeLog:
>>>> 
>>>>       * c-common.cc: Add new __builtin_get_counted_by.
>>>>       * c-common.h (enum rid): Add RID_BUILTIN_GET_COUNTED_BY.
>>>> 
>>>> gcc/c/ChangeLog:
>>>> 
>>>>       * c-decl.cc (names_builtin_p): Add RID_BUILTIN_GET_COUNTED_BY.
>>>>       * c-parser.cc (has_counted_by_object): New routine.
>>>>       (get_counted_by_ref): New routine.
>>>>       (c_parser_postfix_expression): Handle New RID_BUILTIN_GET_COUNTED_BY.
>>>> 
>>>> gcc/ChangeLog:
>>>> 
>>>>       * doc/extend.texi: Add documentation for __builtin_get_counted_by.
>>>> 
>>>> gcc/testsuite/ChangeLog:
>>>> 
>>>>       * gcc.dg/builtin-get-counted-by-1.c: New test.
>>>>       * gcc.dg/builtin-get-counted-by.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                             | 72 +++++++++++++++
>>>> gcc/doc/extend.texi                           | 55 +++++++++++
>>>> .../gcc.dg/builtin-get-counted-by-1.c         | 91 +++++++++++++++++++
>>>> gcc/testsuite/gcc.dg/builtin-get-counted-by.c | 54 +++++++++++
>>>> 7 files changed, 275 insertions(+)
>>>> create mode 100644 gcc/testsuite/gcc.dg/builtin-get-counted-by-1.c
>>>> create mode 100644 gcc/testsuite/gcc.dg/builtin-get-counted-by.c
>>>> 
>>>> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
>>>> index e7e371fd26f..4b27c6bfeeb 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_get_counted_by", RID_BUILTIN_GET_COUNTED_BY, 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 2510ee4dbc9..5d5a297012f 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_GET_COUNTED_BY,
>>>>  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 8cef8f2c289..40bc808878b 100644
>>>> --- a/gcc/c/c-decl.cc
>>>> +++ b/gcc/c/c-decl.cc
>>>> @@ -11739,6 +11739,7 @@ names_builtin_p (const char *name)
>>>>    case RID_BUILTIN_SHUFFLE:
>>>>    case RID_BUILTIN_SHUFFLEVECTOR:
>>>>    case RID_BUILTIN_STDC:
>>>> +    case RID_BUILTIN_GET_COUNTED_BY:
>>>>    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 9b9284b1ba4..7b179449fb0 100644
>>>> --- a/gcc/c/c-parser.cc
>>>> +++ b/gcc/c/c-parser.cc
>>>> @@ -10646,6 +10646,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.
>>>> @@ -11740,6 +11769,49 @@ c_parser_postfix_expression (c_parser *parser)
>>>>           set_c_expr_source_range (&expr, loc, close_paren_loc);
>>>>           break;
>>>>         }
>>>> +       case RID_BUILTIN_GET_COUNTED_BY:
>>>> +         {
>>>> +           vec<c_expr_t, va_gc> *cexpr_list;
>>>> +           c_expr_t *e_p;
>>>> +           location_t close_paren_loc;
>>>> +
>>>> +           c_parser_consume_token (parser);
>>>> +           if (!c_parser_get_builtin_args (parser,
>>>> +                                           "__builtin_get_counted_by",
>>>> +                                           &cexpr_list, false,
>>>> +                                           &close_paren_loc))
>>>> +             {
>>>> +               expr.set_error ();
>>>> +               break;
>>>> +             }
>>>> +           if (vec_safe_length (cexpr_list) != 1)
>>>> +             {
>>>> +               error_at (loc, "wrong number of arguments to "
>>>> +                              "%<__builtin_get_counted_by%>");
>>>> +               expr.set_error ();
>>>> +               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_get_counted_by%>");
>>>> +               expr.set_error ();
>>>> +               break;
>>>> +             }
>>>> +
>>>> +           else 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 (size_type_node), 0);
>>>> +
>>>> +           set_c_expr_source_range (&expr, loc, close_paren_loc);
>>>> +           break;
>>>> +         }
>>>>       case RID_BUILTIN_SHUFFLE:
>>>>         {
>>>>           vec<c_expr_t, va_gc> *cexpr_list;
>>>> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
>>>> index 48b27ff9f39..485f6f8dd8d 100644
>>>> --- a/gcc/doc/extend.texi
>>>> +++ b/gcc/doc/extend.texi
>>>> @@ -15198,6 +15198,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_get_counted_by (@var{ptr})}
>>>> +The built-in function @code{__builtin_get_counted_by} 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 pointer type pointing to
>>>> +the @var{size_t} in case of a NULL pointer being returned.
>>>> +
>>>> +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_get_counted_by (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_get_counted_by (q->array)
>>>> +@end smallexample
>>>> +
>>>> +@noindent
>>>> +returns a NULL pointer with type @code{size_t *}.
>>>> +
>>>> +@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-get-counted-by-1.c 
>>>> b/gcc/testsuite/gcc.dg/builtin-get-counted-by-1.c
>>>> new file mode 100644
>>>> index 00000000000..fb195f03970
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.dg/builtin-get-counted-by-1.c
>>>> @@ -0,0 +1,91 @@
>>>> +/* Test the code generation for the new __builtin_get_counted_by.  */
>>>> +/* { 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 MY_ALLOC(P, FAM, COUNT) ({ \
>>>> +  typeof(P) __p; \
>>>> +  size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \
>>>> +  __p = (typeof(P)) __builtin_malloc(__size); \
>>>> +  __builtin_memset(__p, 0, __size); \
>>>> +  if (__builtin_get_counted_by (__p->FAM)) \
>>>> +  *(__builtin_get_counted_by(__p->FAM)) = COUNT; \
>>>> +  P = __p; \
>>>> +})
>>>> +
>>>> +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-get-counted-by.c 
>>>> b/gcc/testsuite/gcc.dg/builtin-get-counted-by.c
>>>> new file mode 100644
>>>> index 00000000000..5eca12bc992
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.dg/builtin-get-counted-by.c
>>>> @@ -0,0 +1,54 @@
>>>> +/* Testing the correct usage of the new __builtin_get_counted_by.  */
>>>> +/* { 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 MY_ALLOC(P, FAM, COUNT) ({ \
>>>> +  typeof(P) __p; \
>>>> +  size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \
>>>> +  __p = (typeof(P)) __builtin_malloc(__size); \
>>>> +  if (__builtin_get_counted_by (__p->FAM)) \
>>>> +    *(__builtin_get_counted_by(__p->FAM)) = COUNT; \
>>>> +  __p; \
>>>> +})
>>>> +
>>>> +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_get_counted_by (); /* { dg-error "wrong number of arguments 
>>>> to" } */
>>>> +  __builtin_get_counted_by (array_annotated->c, 10); /* { dg-error "wrong 
>>>> number of arguments to" } */
>>>> +  __builtin_get_counted_by (array_annotated->other); /* { dg-error "the 
>>>> argument must be an array" } */
>>>> +  __builtin_get_counted_by (foo());  /* { dg-error "the argument must be 
>>>> an array" } */
>>>> +
>>>> +  return 0;
>>>> +}
>>>> --
>>>> 2.31.1


Reply via email to