__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