On Mon, Jul 29, 2024 at 10:55 AM Alejandro Colomar <[email protected]> wrote:
>
> Hi Richard,
>
> On Mon, Jul 29, 2024 at 10:27:35AM GMT, Richard Biener wrote:
> > On Sun, Jul 28, 2024 at 4:16 PM Alejandro Colomar <[email protected]> wrote:
> > >
> > > There were two identical definitions, and none of them are available
> > > where they are needed for implementing _Lengthof(). Merge them, and
> > > provide the single definition in gcc/tree.{h,cc}, where it's available
> > > for _Lengthof().
> > >
> > > Signed-off-by: Alejandro Colomar <[email protected]>
> > > ---
> > > gcc/cp/cp-tree.h | 1 -
> > > gcc/cp/tree.cc | 13 -------------
> > > gcc/rust/backend/rust-tree.cc | 13 -------------
> > > gcc/rust/backend/rust-tree.h | 2 --
> > > gcc/tree.cc | 13 +++++++++++++
> > > gcc/tree.h | 1 +
> > > 6 files changed, 14 insertions(+), 29 deletions(-)
> > >
>
> [...]
>
> > > diff --git a/gcc/tree.cc b/gcc/tree.cc
> > > index 2d2d5b6db6e..3b0adb4cd9f 100644
> > > --- a/gcc/tree.cc
> > > +++ b/gcc/tree.cc
> > > @@ -3729,6 +3729,19 @@ array_type_nelts (const_tree type)
> > > ? max
> > > : fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
> > > }
> > > +
> > > +/* Return, as an INTEGER_CST node, the number of elements for TYPE
> > > + (which is an ARRAY_TYPE). This counts only elements of the top
> > > + array. */
> > > +
> > > +tree
> > > +array_type_nelts_top (tree type)
> > > +{
> > > + return fold_build2_loc (input_location,
> > > + PLUS_EXPR, sizetype,
> > > + array_type_nelts (type),
> > > + size_one_node);
> > > +}
> >
> > But this is now extremely confusing API with array_type_nelts above this
> > saying
> >
> > /* Return, as a tree node, the number of elements for TYPE (which is an
> > ARRAY_TYPE) minus one. This counts only elements of the top array. */
> >
> > so both are "_top". And there's build_array_type_nelts that's taking
> > the number of elements.
> >
> > Can you please rename the existing array_type_nelts to
> > array_type_nelts_minus_one? Then _top could be dropped as well from
> > the alternate API you add.
>
> I wanted to do that, but then I found other functions that are named
> similarly, such as build_array_type_nelts(), and thought that I wasn't
> sure if all of them should be renamed to _minus_one, or just some. So
> I decided to start without renaming.
Just array_type_nelts needs renaming, build_array_type_nelts is fine.
> But yeah, I think I should rename. I'll prepare a patch for renaming it
> independently of this patch set, and send it to be merged before this
> patch set.
Thanks.
> > I'll also note since array_type_nelts_top calls the other function and that
> > has
> >
> > /* If they did it with unspecified bounds, then we should have already
> > given an error about it before we got here. */
> > if (! TYPE_DOMAIN (type))
> > return error_mark_node;
> >
> > the function should handle error_mark_node (and pass that down).
>
> Hmmmm, now I understand that (! TYPE_DOMAIN (type))
>
> $ grep -rn return.array_type_nelts gcc
> gcc/cp/call.cc:12111: return array_type_nelts_top (c->type);
> gcc/c-family/c-common.cc:4090: return array_type_nelts_top (type);
>
> $ sed -n 12102,12119p gcc/cp/call.cc
> /* Return a tree representing the number of elements initialized by
> the
> list-initialization C. The caller must check that C converts to an
> array type. */
>
> static tree
> nelts_initialized_by_list_init (conversion *c)
> {
> /* If the array we're converting to has a dimension, we'll use
> that. */
> if (TYPE_DOMAIN (c->type))
> return array_type_nelts_top (c->type);
> else
> {
> /* Otherwise, we look at how many elements the constructor we're
> initializing from has. */
> tree ctor = conv_get_original_expr (c);
> return size_int (CONSTRUCTOR_NELTS (ctor));
> }
> }
The point is that if you make this a general API it should be safe to be used,
not depending on constraints that are apparently checked right now.
> It seems that would fail when measuring for example
>
> #define memberof(T, member) ((T){}.member)
>
> struct s {
> int x;
> int a[];
> };
>
> __lengthof__(memberof(struct s, a));
>
> I guess?
>
> $ cat len.c
> #include <stdio.h>
>
> #define memberof(T, member) ((T){}.member)
>
> struct s {
> int x;
> int y[];
> };
>
> int
> main(int argc, char *argv[argc + 1])
> {
> int a[42];
> size_t n;
>
> (void) argv;
>
> //n = __lengthof__(argv);
> //printf("__lengthof__(argv) == %zu\n", n);
>
> n = __lengthof__(a);
> printf("lengthof(a):\t %zu\n", n);
>
> n = __lengthof__(long [99]);
> printf("lengthof(long [99]):\t %zu\n", n);
>
> n = __lengthof__(short [n - 10]);
> printf("lengthof(short [n - 10]):\t %zu\n", n);
>
> int b[n / 2];
> n = __lengthof__(b);
> printf("lengthof(b):\t %zu\n", n);
>
> n = __lengthof__(memberof(struct s, y));
> printf("lengthof(memberof(struct s, y)):\t %zu\n", n);
> }
> alx@debian:~/tmp/gcc$ /opt/local/gnu/gcc/lengthof/bin/gcc len.c
> alx@debian:~/tmp/gcc$ ./a.out
> lengthof(a): 42
> lengthof(long [99]): 99
> lengthof(short [n - 10]): 89
> lengthof(b): 44
> lengthof(memberof(struct s, y)): 44
>
> Indeed, it's misbehaving. I'll have a look at that. I'll probably have
> to add an error similar to sizeof's one:
>
> len.c: In function ‘main’:
> len.c:37:19: error: invalid application of ‘sizeof’ to incomplete type ‘int[]’
> 37 | n = sizeof(memberof(struct s, y));
> | ^
>
> Thanks!
>
> >
> > Note array_type_nelts returns nelts - 1 because that avoids building
> > a new tree node for arrays with lower bound zero.
>
> What does it mean that the lower bound is zero? I didn't understand
> that part.
It means the function can return TYPE_MAX_VALUE of the TYPE_DOMAIN
unchanged.
Richard.
> >
> > Thanks,
> > Richard.
> >
> > > /* If arg is static -- a reference to an object in static storage -- then
> > > return the object. This is not the same as the C meaning of `static'.
>
> Have a lovely day!
> Alex
>
> --
> <https://www.alejandro-colomar.es/>