> 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