__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