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 [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 56C613858D29 for ; Thu, 23 Sep 2021 21:37:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 56C613858D29 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-413-5uTM4aVyMjqTRXRoOp8C5w-1; Thu, 23 Sep 2021 17:37:42 -0400 X-MC-Unique: 5uTM4aVyMjqTRXRoOp8C5w-1 Received: by mail-qk1-f198.google.com with SMTP id r5-20020a05620a298500b0045dac5fb940so9036134qkp.17 for ; Thu, 23 Sep 2021 14:37:42 -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=NqNpcVIeAbP0L8x0E3BYx50AmJCnfLGtXrs2WDnoCoE=; b=UAHRTfEm+gkBJMPSBzpcSgV5Qf/MUxyZNM6ZLcLShRhtYkdT6iciHKeowavoCKEMUc vk0vnpxXz41XRl5Urqy/AEf99K4BLLVduz5DXbl2XNL9YkAwollbb+34eAefVqwMzv9X wdJP8rdcgJ1MZaKZnz3NXYKtrH4RqtKxncg5abfT7W/5TePtYqsnY245DgMkoNvY+vK4 Gj9h2lhL5z3t0TuaGOwtES+73ePPjhYjd7saVYUtOBr65XwyaQkwXr0w+IOIpUjI9qkr mtrRSvZlxNNdE0PH7zlQA5M6dgWN0VsQy88lLkjrYK9/ajdUzmuuG1cnRS6MJaASVyfi tzdg== X-Gm-Message-State: AOAM532HeIz8TxUyOOC2jkIeFJpemsZ3vSSXwghBCzKd6YKeL6TL0jlI 8reDCHB2s7LJwYWFqc9/XVv2Go7UgZgRsqs5r/K7F9uezTh2f6EBOu97/H8qyI095RDF+FsiK0O PiaJ0kmGEycaDy5rENw== X-Received: by 2002:a37:a215:: with SMTP id l21mr7109703qke.74.1632433062141; Thu, 23 Sep 2021 14:37:42 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwXZYGQmoGGQqMnu9xKMovVMvHi/Xir1hEIdRN+HP73ENCjQ84ITgNK7DAFpq/j3Qjun8c4Lw== X-Received: by 2002:a37:a215:: with SMTP id l21mr7109658qke.74.1632433061599; Thu, 23 Sep 2021 14:37:41 -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 h2sm5506877qkf.106.2021.09.23.14.37.40 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 23 Sep 2021 14:37:40 -0700 (PDT) Message-ID: Date: Thu, 23 Sep 2021 17:37:39 -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> <8c83fd5f-9504-cb26-c459-b3e606e8304e@redhat.com> <0c584cb2384ad2f0eb51cad43b07e2aac86ad234.camel@med.uni-goettingen.de> From: Jason Merrill In-Reply-To: <0c584cb2384ad2f0eb51cad43b07e2aac86ad234.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: Thu, 23 Sep 2021 21:37:47 -0000 On 9/23/21 15:49, Uecker, Martin wrote: > Am Mittwoch, den 22.09.2021, 17:18 -0400 schrieb Jason Merrill: >> 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? > > I intentionally limited the change to this specific > case to avoid accidentally breaking or pessimizing > anything else. I did not notice any other cases that > need fixing. It is of course possible that > I have missed some... > >> >> Maybe we should include the statement-expr in the SAVE_EXPR? > > I am not really sure how to implement this. Nor am I, I'm not at all familiar with the VLA handling code. But if the generated trees rely on evaluation happening with a stricter order than is actually guaranteed, that seems like a bug in the generation of the expression trees, not the folding code. Could someone that knows more about VLA weigh in? > Maybe we could apply this patch first (because > I have to work around this bug in a couple of > projects which is a bit annoying)? I am happy > to implement an alternative later if there is > a better way (which I can understand). The gimplify_compound_lval change is OK now. What's the rationale for the gimplify_target_expr change? >>> { >>> 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(); >>> +} >>> + >>>