Am Montag, den 08.11.2021, 19:13 +0100 schrieb Martin Uecker:
> Am Montag, den 08.11.2021, 12:13 -0500 schrieb Jason Merrill:
> > On 11/7/21 01:40, Uecker, Martin wrote:
> > > Am Mittwoch, den 03.11.2021, 10:18 -0400 schrieb Jason Merrill:
> 
> ...
> 
> > > Thank you! I made these changes and ran
> > > bootstrap and tests again.
> > 
> > Hmm, it doesn't look like you made the change to use the save_expr 
> > function instead of build1?
> 
> Oh, sorry. I wanted to change it and then forgot.
> Now also with this change (changelog as before).


Ok, with is this change?

Best,
Martin



> > > Ok for trunk?
> > > 
> > > 
> > > Any idea how to fix returning structs with
> > > VLA member from statement expressions?
> > 
> > Testcase?
> 
> void foo(void)
> {
>       ({ int N = 3; struct { char x[N]; } x; x; });
> }
> 
> The difference to the tests in this patch (which
> also forgot to include in the last version) is that
> the object of variable size is returned from the
> statement expression and not a pointer to it.
> This can not happen with arrays because they decay
> to pointers.
> 
> 
> Martin
> 
> 
> > > Otherwise, I will add an error message to
> > > the FE in another patch.
> > > 
> > > Martin
> > > 
> 
> diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
> index 436df45df68..95083f95442 100644
> --- a/gcc/c-family/c-common.c
> +++ b/gcc/c-family/c-common.c
> @@ -3306,7 +3306,19 @@ pointer_int_sum (location_t loc, enum tree_code 
> resultcode,
>                                TREE_TYPE (result_type)))
>      size_exp = integer_one_node;
>    else
> -    size_exp = size_in_bytes_loc (loc, TREE_TYPE (result_type));
> +    {
> +      size_exp = size_in_bytes_loc (loc, TREE_TYPE (result_type));
> +      /* Wrap the pointer expression in a SAVE_EXPR to make sure it
> +      is evaluated first when the size expression may depend
> +      on it for VM types.  */
> +      if (TREE_SIDE_EFFECTS (size_exp)
> +       && TREE_SIDE_EFFECTS (ptrop)
> +       && variably_modified_type_p (TREE_TYPE (ptrop), NULL))
> +     {
> +       ptrop = save_expr (ptrop);
> +       size_exp = build2 (COMPOUND_EXPR, TREE_TYPE (intop), ptrop, size_exp);
> +     }
> +    }
>  
>    /* We are manipulating pointer values, so we don't need to warn
>       about relying on undefined signed overflow.  We disable the
> diff --git a/gcc/gimplify.c b/gcc/gimplify.c
> index c2ab96e7e18..84f7dc3c248 100644
> --- a/gcc/gimplify.c
> +++ b/gcc/gimplify.c
> @@ -2964,7 +2964,9 @@ gimplify_var_or_parm_decl (tree *expr_p)
>       declaration, for which we've already issued an error.  It would
>       be really nice if the front end wouldn't leak these at all.
>       Currently the only known culprit is C++ destructors, as seen
> -     in g++.old-deja/g++.jason/binding.C.  */
> +     in g++.old-deja/g++.jason/binding.C.
> +     Another possible culpit are size expressions for variably modified
> +     types which are lost in the FE or not gimplified correctly.  */
>    if (VAR_P (decl)
>        && !DECL_SEEN_IN_BIND_EXPR_P (decl)
>        && !TREE_STATIC (decl) && !DECL_EXTERNAL (decl)
> @@ -3109,16 +3111,22 @@ gimplify_compound_lval (tree *expr_p, gimple_seq 
> *pre_p, gimple_seq
> *post_p,
>       expression until we deal with any variable bounds, sizes, or
>       positions in order to deal with PLACEHOLDER_EXPRs.
>  
> -     So we do this in three steps.  First we deal with the annotations
> -     for any variables in the components, then we gimplify the base,
> -     then we gimplify any indices, from left to right.  */
> +     The base expression may contain a statement expression that
> +     has declarations used in size expressions, so has to be
> +     gimplified before gimplifying the size expressions.
> +
> +     So we do this in three steps.  First we deal with variable
> +     bounds, sizes, and positions, then we gimplify the base,
> +     then we deal with the annotations for any variables in the
> +     components and any indices, from left to right.  */
> +
>    for (i = expr_stack.length () - 1; i >= 0; i--)
>      {
>        tree t = expr_stack[i];
>  
>        if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
>       {
> -       /* Gimplify the low bound and element type size and put them into
> +       /* Deal with the low bound and element type size and put them into
>            the ARRAY_REF.  If these values are set, they have already been
>            gimplified.  */
>         if (TREE_OPERAND (t, 2) == NULL_TREE)
> @@ -3127,18 +3135,8 @@ gimplify_compound_lval (tree *expr_p, gimple_seq 
> *pre_p, gimple_seq
> *post_p,
>             if (!is_gimple_min_invariant (low))
>               {
>                 TREE_OPERAND (t, 2) = low;
> -               tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p,
> -                                     post_p, is_gimple_reg,
> -                                     fb_rvalue);
> -               ret = MIN (ret, tret);
>               }
>           }
> -       else
> -         {
> -           tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
> -                                 is_gimple_reg, fb_rvalue);
> -           ret = MIN (ret, tret);
> -         }
>  
>         if (TREE_OPERAND (t, 3) == NULL_TREE)
>           {
> @@ -3155,18 +3153,8 @@ gimplify_compound_lval (tree *expr_p, gimple_seq 
> *pre_p, gimple_seq
> *post_p,
>                                             elmt_size, factor);
>  
>                 TREE_OPERAND (t, 3) = elmt_size;
> -               tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p,
> -                                     post_p, is_gimple_reg,
> -                                     fb_rvalue);
> -               ret = MIN (ret, tret);
>               }
>           }
> -       else
> -         {
> -           tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p,
> -                                 is_gimple_reg, fb_rvalue);
> -           ret = MIN (ret, tret);
> -         }
>       }
>        else if (TREE_CODE (t) == COMPONENT_REF)
>       {
> @@ -3186,18 +3174,8 @@ gimplify_compound_lval (tree *expr_p, gimple_seq 
> *pre_p, gimple_seq
> *post_p,
>                                          offset, factor);
>  
>                 TREE_OPERAND (t, 2) = offset;
> -               tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p,
> -                                     post_p, is_gimple_reg,
> -                                     fb_rvalue);
> -               ret = MIN (ret, tret);
>               }
>           }
> -       else
> -         {
> -           tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
> -                                 is_gimple_reg, fb_rvalue);
> -           ret = MIN (ret, tret);
> -         }
>       }
>      }
>  
> @@ -3208,21 +3186,34 @@ gimplify_compound_lval (tree *expr_p, gimple_seq 
> *pre_p, gimple_seq
> *post_p,
>                       fallback | fb_lvalue);
>    ret = MIN (ret, tret);
>  
> -  /* And finally, the indices and operands of ARRAY_REF.  During this
> -     loop we also remove any useless conversions.  */
> +  /* Step 3: gimplify size expressions and the indices and operands of
> +     ARRAY_REF.  During this loop we also remove any useless conversions.  */
> +
>    for (; expr_stack.length () > 0; )
>      {
>        tree t = expr_stack.pop ();
>  
>        if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
>       {
> +       /* Gimplify the low bound and element type size. */
> +       tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
> +                             is_gimple_reg, fb_rvalue);
> +       ret = MIN (ret, tret);
> +
> +       tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p,
> +                             is_gimple_reg, fb_rvalue);
> +       ret = MIN (ret, tret);
> +
>         /* Gimplify the dimension.  */
> -       if (!is_gimple_min_invariant (TREE_OPERAND (t, 1)))
> -         {
> -           tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
> -                                 is_gimple_val, fb_rvalue);
> -           ret = MIN (ret, tret);
> -         }
> +       tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
> +                             is_gimple_val, fb_rvalue);
> +       ret = MIN (ret, tret);
> +     }
> +      else if (TREE_CODE (t) == COMPONENT_REF)
> +     {
> +       tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
> +                             is_gimple_reg, fb_rvalue);
> +       ret = MIN (ret, tret);
>       }
>  
>        STRIP_USELESS_TYPE_CONVERSION (TREE_OPERAND (t, 0));
> @@ -6927,6 +6918,8 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, 
> gimple_seq *post_p)
>       {
>         if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (temp)))
>           gimplify_type_sizes (TREE_TYPE (temp), pre_p);
> +       /* FIXME: this is correct only when the size of the type does
> +          not depend on expressions evaluated in init.  */
>         gimplify_vla_decl (temp, pre_p);
>       }
>        else
> diff --git a/gcc/testsuite/gcc.dg/vla-stexp-3.c 
> b/gcc/testsuite/gcc.dg/vla-stexp-3.c
> new file mode 100644
> index 00000000000..e663de1cd72
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vla-stexp-3.c
> @@ -0,0 +1,11 @@
> +/* PR91038 */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +
> +void bar(void)
> +{
> +     ({ int N = 2; int (*x)[9][N] = 0; x; })[1];
> +     ({ int N = 2; int (*x)[9][N] = 0; x; })[0];     // should not ice
> +}
> +
> diff --git a/gcc/testsuite/gcc.dg/vla-stexp-4.c 
> b/gcc/testsuite/gcc.dg/vla-stexp-4.c
> new file mode 100644
> index 00000000000..612b5a802fc
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vla-stexp-4.c
> @@ -0,0 +1,94 @@
> +/* PR29970, PR91038 */
> +/* { dg-do run } */
> +/* { dg-options "-O0 -Wunused-variable" } */
> +
> +int foo3b(void)   // should not return 0
> +{
> +        int n = 0;
> +        return sizeof *({ n = 10; int x[n]; &x; });
> +}
> +
> +int foo4(void)   // should not ICE
> +{
> +        return (*({
> +                        int n = 20;
> +                        char (*x)[n][n] = __builtin_malloc(n * n);
> +                        (*x)[12][1] = 1;
> +                        x;
> +                }))[12][1];
> +}
> +
> +int foo5(void)   // should return 1, returns 0
> +{
> +        int n = 0;
> +        return (*({
> +                        n = 20;
> +                        char (*x)[n][n] = __builtin_malloc(n * n);
> +                        (*x)[12][1] = 1;
> +                        (*x)[0][1] = 0;
> +                        x;
> +                }))[12][1];
> +}
> +
> +int foo5c(void)   // should return 400 
> +{
> +        int n = 0;
> +        return sizeof(*({
> +                        n = 20;
> +                        char (*x)[n][n] = __builtin_malloc(n * n);
> +                        (*x)[12][1] = 1;
> +                        (*x)[0][1] = 0;
> +                        x;
> +                }));
> +}
> +
> +int foo5b(void)   // should return 1, returns 0
> +{
> +     int n = 0;                      /* { dg-warning "unused variable" } */
> +        return (*({
> +                        int n = 20;
> +                        char (*x)[n][n] = __builtin_malloc(n * n);
> +                        (*x)[12][1] = 1;
> +                        (*x)[0][1] = 0;
> +                        x;
> +                }))[12][1];
> +}
> +
> +int foo5a(void)   // should return 1, returns 0
> +{
> +        return (*({
> +                        int n = 20;
> +                        char (*x)[n][n] = __builtin_malloc(n * n);
> +                        (*x)[12][1] = 1;
> +                        (*x)[0][1] = 0;
> +                        x;
> +                }))[12][1];
> +}
> +
> +
> +
> +
> +int main()
> +{
> +     if (sizeof(int[10]) != foo3b())
> +             __builtin_abort();
> +
> +     if (1 != foo4())
> +             __builtin_abort();
> +
> +     if (400 != foo5c())
> +             __builtin_abort();
> +
> +     if (1 != foo5a())
> +             __builtin_abort();
> +
> +     if (1 != foo5b()) // -O0
> +             __builtin_abort();
> +
> +     if (1 != foo5())
> +             __builtin_abort();
> +
> +     return 0;
> +}
> +
> +
> diff --git a/gcc/testsuite/gcc.dg/vla-stexp-5.c 
> b/gcc/testsuite/gcc.dg/vla-stexp-5.c
> new file mode 100644
> index 00000000000..d6a7f2b34b8
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vla-stexp-5.c
> @@ -0,0 +1,30 @@
> +/* PR29970 */
> +/* { dg-do run } */
> +/* { dg-options "-Wunused-variable" } */
> +
> +
> +
> +
> +int foo2a(void)   // should not ICE
> +{
> +        return ({ int n = 20; struct { int x[n];} x; x.x[12] = 1; sizeof(x); 
> });
> +}
> +
> +
> +int foo2b(void)   // should not ICE
> +{
> +        return sizeof *({ int n = 20; struct { int x[n];} x; x.x[12] = 1; 
> &x; });
> +}
> +
> +int main()
> +{
> +     if (sizeof(struct { int x[20]; }) != foo2a())
> +             __builtin_abort();
> +
> +     if (sizeof(struct { int x[20]; }) != foo2b())
> +             __builtin_abort();
> +
> +     return 0;
> +}
> +
> +
> diff --git a/gcc/testsuite/gcc.dg/vla-stexp-6.c 
> b/gcc/testsuite/gcc.dg/vla-stexp-6.c
> new file mode 100644
> index 00000000000..3d96d38898b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vla-stexp-6.c
> @@ -0,0 +1,94 @@
> +/* PR29970, PR91038 */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wunused-variable" } */
> +
> +int foo3b(void)   // should not return 0
> +{
> +        int n = 0;
> +        return sizeof *({ n = 10; int x[n]; &x; });
> +}
> +
> +int foo4(void)   // should not ICE
> +{
> +        return (*({
> +                        int n = 20;
> +                        char (*x)[n][n] = __builtin_malloc(n * n);
> +                        (*x)[12][1] = 1;
> +                        x;
> +                }))[12][1];
> +}
> +
> +int foo5(void)   // should return 1, returns 0
> +{
> +        int n = 0;
> +        return (*({
> +                        n = 20;
> +                        char (*x)[n][n] = __builtin_malloc(n * n);
> +                        (*x)[12][1] = 1;
> +                        (*x)[0][1] = 0;
> +                        x;
> +                }))[12][1];
> +}
> +
> +int foo5c(void)   // should return 400 
> +{
> +        int n = 0;
> +        return sizeof(*({
> +                        n = 20;
> +                        char (*x)[n][n] = __builtin_malloc(n * n);
> +                        (*x)[12][1] = 1;
> +                        (*x)[0][1] = 0;
> +                        x;
> +                }));
> +}
> +
> +int foo5b(void)   // should return 1, returns 0
> +{
> +     int n = 0;      /* { dg-warning "unused variable" } */
> +        return (*({
> +                        int n = 20;
> +                        char (*x)[n][n] = __builtin_malloc(n * n);
> +                        (*x)[12][1] = 1;
> +                        (*x)[0][1] = 0;
> +                        x;
> +                }))[12][1];
> +}
> +
> +int foo5a(void)   // should return 1, returns 0
> +{
> +        return (*({
> +                        int n = 20;
> +                        char (*x)[n][n] = __builtin_malloc(n * n);
> +                        (*x)[12][1] = 1;
> +                        (*x)[0][1] = 0;
> +                        x;
> +                }))[12][1];
> +}
> +
> +
> +
> +
> +int main()
> +{
> +     if (sizeof(int[10]) != foo3b())
> +             __builtin_abort();
> +
> +     if (1 != foo4())
> +             __builtin_abort();
> +
> +     if (400 != foo5c())
> +             __builtin_abort();
> +
> +     if (1 != foo5a())
> +             __builtin_abort();
> +
> +     if (1 != foo5b()) // -O0
> +             __builtin_abort();
> +
> +     if (1 != foo5())
> +             __builtin_abort();
> +
> +     return 0;
> +}
> +
> +
> diff --git a/gcc/testsuite/gcc.dg/vla-stexp-7.c 
> b/gcc/testsuite/gcc.dg/vla-stexp-7.c
> new file mode 100644
> index 00000000000..3091b9184c2
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vla-stexp-7.c
> @@ -0,0 +1,44 @@
> +/* PR91038 */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wunused-variable" } */
> +
> +
> +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
> +
> +struct lbm {
> +
> +     int D;
> +     const int* DQ;
> +
> +} D2Q9 = { 2,
> +     (const int*)&(const int[9][2]){
> +             { 0, 0 },
> +             { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 },
> +             { 1, 1 }, { -1, 1 }, { -1, -1 }, { 1, -1 },
> +     }
> +};
> +
> +void zouhe_left(void)
> +{
> +     __auto_type xx = (*({ int N = 2; struct lbm __x = D2Q9; ((const 
> int(*)[9][N])__x.DQ); }));
> +
> +     if (1 != xx[1][0])
> +             __builtin_abort();
> +
> +     if (2 != ARRAY_SIZE(xx[1]))
> +             __builtin_abort();
> +
> +     if (1 != (*({ int N = 2; struct lbm __x = D2Q9; ((const 
> int(*)[9][N])__x.DQ); }))[1][0])
> +             __builtin_abort();
> +
> +     if (2 != ARRAY_SIZE(*({ int N = 2; struct lbm __x = D2Q9; ((const 
> int(*)[9][N])__x.DQ);
> })[1]))
> +             __builtin_abort();
> +}
> +
> +int main()
> +{
> +     zouhe_left();
> +     return 0;
> +}
> +
> +
> diff --git a/gcc/testsuite/gcc.dg/vla-stexp-8.c 
> b/gcc/testsuite/gcc.dg/vla-stexp-8.c
> new file mode 100644
> index 00000000000..5b475eb6cf2
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vla-stexp-8.c
> @@ -0,0 +1,47 @@
> +/* PR29970, PR91038 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -Wunused-variable" } */
> +
> +
> +int foo0(void)
> +{
> +     int c = *(*(*({ int n = 10; int (*x)[n][n] = __builtin_malloc(sizeof 
> *x); x; }) + 5) + 5);
> +     return c;
> +}
> +
> +int foo1(void)
> +{
> +     int c = *(5 + *(5 + *({ int n = 10; int (*x)[n][n] = 
> __builtin_malloc(sizeof *x); x; })));
> +     return c;
> +}
> +
> +int bar2(void)
> +{
> +     int c = (*({ int n = 10; struct { int y[n]; int z; }* x = 
> __builtin_malloc(sizeof *x); x;
> })).z;
> +     return c;
> +}
> +
> +int bar3(void)
> +{
> +     int n = 2;      /* { dg-warning "unused variable" } */
> +     int c = (*({ int n = 3;         /* { dg-warning "unused variable" } */
> +             ({ int n = 10; int (*x)[n][n] = __builtin_malloc(sizeof *x); x; 
> }); }))[5][5];
> +     return c;
> +}
> +
> +int bar3b(void)
> +{
> +     int n = 2;      /* { dg-warning "unused variable" } */
> +     int c = (*({ int n = 3;         /* { dg-warning "unused variable" } */
> +             ({ int n = 10; int (*x)[n][n] = __builtin_malloc(sizeof *x); x; 
> }); }))[0][0];
> +     return c;
> +}
> +
> +int bar4(void)
> +{
> +     int n = 2;      /* { dg-warning "unused variable" } */
> +     int c = *(5 + *( 5 + *({ int n = 3;     /* { dg-warning "unused 
> variable" } */
> +             ({ int n = 10; int (*x)[n][n] = __builtin_malloc(sizeof *x); x; 
> }); })));
> +     return c;
> +}
> +
> diff --git a/gcc/testsuite/gcc.dg/vla-stexp-9.c 
> b/gcc/testsuite/gcc.dg/vla-stexp-9.c
> new file mode 100644
> index 00000000000..3593a790785
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vla-stexp-9.c
> @@ -0,0 +1,53 @@
> +/* PR91038 */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wunused-variable" } */
> +
> +
> +
> +void foo(void)
> +{
> +     if (2 * sizeof(int) != sizeof((*({ int N = 2; int (*x)[9][N] = 0; x; 
> })[1])))
> +             __builtin_abort();
> +}
> +
> +void bar(void)
> +{
> +     if (2 * sizeof(int) != sizeof((*({ int N = 2; int (*x)[9][N] = 0; x; 
> })[0])))
> +             __builtin_abort();
> +}
> +
> +void bar0(void)
> +{
> +     if (2 * 9 *  sizeof(int) != sizeof((*({ int N = 2; int (*x)[9][N] = 0; 
> x; }))))
> +             __builtin_abort();
> +}
> +
> +void bar11(void)
> +{
> +     sizeof(*((*({ int N = 2; int (*x)[9][N] = 0; x; }) + 0)));
> +}
> +
> +void bar12(void)
> +{
> +     if (2 * sizeof(int) != sizeof(*((*({ int N = 2; int (*x)[9][N] = 0; x; 
> })    ))))
> +             __builtin_abort();
> +}
> +
> +void bar1(void)
> +{
> +     if (2 * sizeof(int) != sizeof(*((*({ int N = 2; int (*x)[9][N] = 0; x; 
> }) + 0))))
> +             __builtin_abort();
> +}
> +
> +
> +
> +
> +int main()
> +{
> +     foo();
> +     bar0();
> +     bar12();
> +     bar1();
> +     bar();
> +}
> +
> 

Reply via email to