From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 74DFE3858401 for ; Wed, 22 Sep 2021 21:18:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 74DFE3858401 Received: from mail-qk1-f198.google.com (mail-qk1-f198.google.com [209.85.222.198]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-410-ggaLOP0yPnKc5LfyLGuoVQ-1; Wed, 22 Sep 2021 17:18:49 -0400 X-MC-Unique: ggaLOP0yPnKc5LfyLGuoVQ-1 Received: by mail-qk1-f198.google.com with SMTP id e22-20020a05620a209600b003d5ff97bff7so13483708qka.1 for ; Wed, 22 Sep 2021 14:18:49 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:date:mime-version:user-agent:subject :content-language:to:cc:references:from:in-reply-to :content-transfer-encoding; bh=sVkoiIvZ3/GQdFJ5kFZEt1ZJzkkKqG79HN3Cpj61GZs=; b=iOq340kdgrxKuOK/iZEL+rd/JCH/Ia9lngZGVRHBDH5StLPSzMeEyH9GELqLTndVYx PmyFq0fUcTP7Nz6LoSgVweJltQKXgmNsHYor/XclmaGUcu/ENJv8LkA98RSrQC0QKXiW bpf37MsXjZlImX75CAsYz8q9uIUvQv60lVw+AM9Tv0egPu85rnTXG/Hp/vg+ZzfAUgEN O+XEV3zs8Kj6DORGX1J5bkB7qppsqUgW57RsVjTNhhkoZTVNin1kcykXKLFZA4oOr2ge M8eq9aqq6AP6PH59HO4ocsWa3uU3DsNzBUb5mtKknNv1U8clOr0LgrTNk+try7e2lq0q BvLA== X-Gm-Message-State: AOAM530FppRMBIA6ubFpmFXnUqzcGRLsDyk8phlLylxTdZVBeHAYjTX4 OCP2h6LwxtDxE4Cm5aTyN8uDg8zW4dpHe4+MbEq/ZnPBClPiWsS6Ygg/EfAWeDLNdIOsmzZbS2n 3tqupj9N1qCTVD3QHVg== X-Received: by 2002:a37:747:: with SMTP id 68mr1508232qkh.526.1632345528268; Wed, 22 Sep 2021 14:18:48 -0700 (PDT) X-Google-Smtp-Source: ABdhPJz1j+y0WuWxKomnMd+GPYc2nzRiogmK7MH1kYqly7K/d8y5V+5ih8XZLywQjcxM1n05YNeNhg== X-Received: by 2002:a37:747:: with SMTP id 68mr1508198qkh.526.1632345527826; Wed, 22 Sep 2021 14:18:47 -0700 (PDT) Received: from [192.168.1.149] (130-44-159-43.s15913.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.159.43]) by smtp.gmail.com with ESMTPSA id b79sm2897137qkc.0.2021.09.22.14.18.46 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 22 Sep 2021 14:18:47 -0700 (PDT) Message-ID: <8c83fd5f-9504-cb26-c459-b3e606e8304e@redhat.com> Date: Wed, 22 Sep 2021 17:18:45 -0400 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.1.1 Subject: Re: [PATCH v3] Fix ICE when mixing VLAs and statement expressions [PR91038] To: "Uecker, Martin" , "gcc-patches@gcc.gnu.org" Cc: "kenner@nyu.edu" , "richard.guenther@gmail.com" , "botcazou@adacore.com" References: <81ab80a5704e33a05411918b8a99968c1dd1b041.camel@med.uni-goettingen.de> From: Jason Merrill In-Reply-To: <81ab80a5704e33a05411918b8a99968c1dd1b041.camel@med.uni-goettingen.de> X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, NICE_REPLY_A, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 22 Sep 2021 21:18:52 -0000 On 9/5/21 15:14, Uecker, Martin wrote: > > Here is the third version of the patch. This also > fixes the index zero case. Thus, this should be > a complete fix for 91038 and should fix all cases > also supported by clang. Still not working is > returning a struct of variable size from a > statement expression (29970) when the size depends > on computations inside the statement expression. > > Bootstrapped and regression tested > on x86-64 for all languages. > > Martin > > > > > Fix ICE when mixing VLAs and statement expressions [PR91038] > > When returning VM-types from statement expressions, this can > lead to an ICE when declarations from the statement expression > are referred to later. Most of these issues can be addressed by > gimplifying the base expression earlier in gimplify_compound_lval. > Another issue is fixed by not reording some size-related expressions > during folding. This fixes PR91038 and some of the test cases > from PR29970 (structs with VLA members need further work). > > > 2021-08-01 Martin Uecker > > gcc/ > PR c/91038 > PR c/29970 > * gimplify.c (gimplify_var_or_parm_decl): Update comment. > (gimplify_compound_lval): Gimplify base expression first. > (gimplify_target_expr): Do not gimplify size expression. > * fold-const.c (fold_binary_loc): Do not reorder SAVE_EXPR > in pointer arithmetic for variably modified types. > > gcc/testsuite/ > PR c/91038 > PR c/29970 > * gcc.dg/vla-stexp-3.c: New test. > * gcc.dg/vla-stexp-4.c: New test. > * gcc.dg/vla-stexp-5.c: New test. > * gcc.dg/vla-stexp-6.c: New test. > * gcc.dg/vla-stexp-7.c: New test. > * gcc.dg/vla-stexp-8.c: New test. > * gcc.dg/vla-stexp-9.c: New test. > > > diff --git a/gcc/fold-const.c b/gcc/fold-const.c > index ff23f12f33c..1e6f50692b5 100644 > --- a/gcc/fold-const.c > +++ b/gcc/fold-const.c > @@ -10854,7 +10854,15 @@ fold_binary_loc (location_t loc, enum tree_code code, tree type, > return build2_loc (loc, COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0), > tem); > } > - if (TREE_CODE (arg1) == COMPOUND_EXPR) > + /* This interleaves execution of the two sub-expressions > + which is allowed in C. For pointer arithmetic when the > + the pointer has a variably modified type, the right expression > + might have a SAVE_EXPR which depends on the left expr, so > + do not fold in this case. */ > + if (TREE_CODE (arg1) == COMPOUND_EXPR > + && !(code == POINTER_PLUS_EXPR > + && TREE_CODE (TREE_OPERAND (arg1, 0)) == SAVE_EXPR) > + && variably_modified_type_p (type, NULL_TREE)) This seems pretty fragile. If the problem is that the SAVE_EXPR depends on a statement-expr on the LHS, can't that happen with expressions other than POINTER_PLUS_EXPR? Maybe we should include the statement-expr in the SAVE_EXPR? > { > tem = fold_build2_loc (loc, code, type, op0, > fold_convert_loc (loc, TREE_TYPE (op1), > diff --git a/gcc/gimplify.c b/gcc/gimplify.c > index 99d1c7fcce4..8ee205f593c 100644 > --- a/gcc/gimplify.c > +++ b/gcc/gimplify.c > @@ -2840,7 +2840,10 @@ 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) > @@ -2985,16 +2988,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) > @@ -3003,18 +3012,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) > { > @@ -3031,18 +3030,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) > { > @@ -3062,18 +3051,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); > - } > } > } > > @@ -3084,21 +3063,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)); > @@ -6766,8 +6758,8 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) > to the temps list. Handle also variable length TARGET_EXPRs. */ > if (!poly_int_tree_p (DECL_SIZE (temp))) > { > - 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(); > +} > + >