On Tue, 1 Apr 2025, Jakub Jelinek wrote: > Hi! > > The following testcases ICE on invalid code which defines > labels inside of statement expressions and then uses &&label > from code outside of the statement expressions. > The C++ FE diagnoses that with a warning (not specifically for > assume attribute, genericallly about taking address of a label > outside of a statement expression so computed goto could violate > the requirement that statement expression is not entered from > outside of it through a jump into it), the C FE doesn't diagnose > anything. > Normal direct gotos to such labels are diagnosed by both C and C++. > In the assume attribute case it is actually worse than for > addresses of labels in normal statement expressions, in that case > the labels are still in the current function, so invalid program > can still jump to those (and in case of OpenMP/OpenACC where it > is also invalid and stuff is moved to a separate function, such > movement is done post cfg discovery of FORCED_LABELs and worst > case one can run into cases which fail to assemble, but I haven't > succeeded in creating ICE for that). > For assume at -O0 we'd just throw away the assume expression if > it is not a simple condition and so the label is then not defined > anywhere and we ICE during cfg pass. > The gimplify.cc hunks fix that, as we don't have FORCED_LABELs > discovery done yet, it preserves all assume expressions which contain > used user labels. > With that we ICE during IRA, which is upset about an indirect jump > to a label which doesn't exist. > So, the gimple-low.cc hunks add diagnostics of the problem, it gathers > uids of all the user used labels inside of the assume expressions (usually > none) and if it finds any, walks the IL to find uses of those from outside > of those expressions now outlined into separate magic functions. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
OK. Thanks, Richard. > 2025-04-01 Jakub Jelinek <ja...@redhat.com> > > PR middle-end/119537 > * gimplify.cc (find_used_user_labels): New function. > (gimplify_call_expr): Don't remove complex assume expression at -O0 > if it defines any user labels. > * gimple-low.cc: Include diagnostic-core.h. > (assume_labels): New variable. > (diagnose_assume_labels): New function. > (lower_function_body): Call it via walk_gimple_seq if assume_labels > is non-NULL, then BITMAP_FREE assume_labels. > (find_assumption_locals_r): Record in assume_labels uids of user > labels defined in assume attribute expressions. > > * c-c++-common/pr119537-1.c: New test. > * c-c++-common/pr119537-2.c: New test. > > --- gcc/gimplify.cc.jj 2025-03-31 12:53:44.853727077 +0200 > +++ gcc/gimplify.cc 2025-03-31 17:05:40.854893880 +0200 > @@ -4508,6 +4508,21 @@ gimplify_variant_call_expr (tree expr, f > } > > > +/* Helper function for gimplify_call_expr, called via walk_tree. > + Find used user labels. */ > + > +static tree > +find_used_user_labels (tree *tp, int *, void *) > +{ > + if (TREE_CODE (*tp) == LABEL_EXPR > + && !DECL_ARTIFICIAL (LABEL_EXPR_LABEL (*tp)) > + && DECL_NAME (LABEL_EXPR_LABEL (*tp)) > + && TREE_USED (LABEL_EXPR_LABEL (*tp))) > + return *tp; > + return NULL_TREE; > +} > + > + > /* Gimplify the CALL_EXPR node *EXPR_P into the GIMPLE sequence PRE_P. > WANT_VALUE is true if the result of the call is desired. */ > > @@ -4568,8 +4583,14 @@ gimplify_call_expr (tree *expr_p, gimple > fndecl, 0)); > return GS_OK; > } > - /* If not optimizing, ignore the assumptions. */ > - if (!optimize || seen_error ()) > + /* If not optimizing, ignore the assumptions unless there > + are used user labels in it. */ > + if ((!optimize > + && !walk_tree_without_duplicates (&CALL_EXPR_ARG (*expr_p, > + 0), > + find_used_user_labels, > + NULL)) > + || seen_error ()) > { > *expr_p = NULL_TREE; > return GS_ALL_DONE; > --- gcc/gimple-low.cc.jj 2025-03-21 20:25:38.396064280 +0100 > +++ gcc/gimple-low.cc 2025-03-31 20:20:38.961772695 +0200 > @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. > #include "tree-inline.h" > #include "gimple-walk.h" > #include "attribs.h" > +#include "diagnostic-core.h" > > /* The differences between High GIMPLE and Low GIMPLE are the > following: > @@ -78,6 +79,10 @@ struct lower_data > bool cannot_fallthru; > }; > > +/* Bitmap of LABEL_DECL uids for user labels moved into assume outlined > + functions. */ > +static bitmap assume_labels; > + > static void lower_stmt (gimple_stmt_iterator *, struct lower_data *); > static void lower_gimple_bind (gimple_stmt_iterator *, struct lower_data *); > static void lower_try_catch (gimple_stmt_iterator *, struct lower_data *); > @@ -87,6 +92,29 @@ static void lower_builtin_posix_memalign > static void lower_builtin_assume_aligned (gimple_stmt_iterator *); > > > +/* Helper function for lower_function_body, called via walk_gimple_seq. > + Diagnose uses of user labels defined inside of assume attribute > + expressions. */ > + > +static tree > +diagnose_assume_labels (tree *tp, int *, void *data) > +{ > + if (TREE_CODE (*tp) == LABEL_DECL > + && !DECL_ARTIFICIAL (*tp) > + && DECL_NAME (*tp) > + && bitmap_bit_p (assume_labels, DECL_UID (*tp))) > + { > + struct walk_stmt_info *wi = (struct walk_stmt_info *) data; > + auto_diagnostic_group d; > + error_at (gimple_location (gsi_stmt (wi->gsi)), > + "reference to label %qD defined inside of %<assume%> " > + "attribute expression from outside of the attribute", *tp); > + inform (DECL_SOURCE_LOCATION (*tp), "%qD defined here", *tp); > + } > + return NULL_TREE; > +} > + > + > /* Lower the body of current_function_decl from High GIMPLE into Low > GIMPLE. */ > > @@ -169,6 +197,15 @@ lower_function_body (void) > lowered sequence. */ > gimple_set_body (current_function_decl, lowered_body); > > + if (assume_labels) > + { > + struct walk_stmt_info wi; > + > + memset (&wi, 0, sizeof (wi)); > + walk_gimple_seq (lowered_body, NULL, diagnose_assume_labels, &wi); > + BITMAP_FREE (assume_labels); > + } > + > gcc_assert (data.block == DECL_INITIAL (current_function_decl)); > BLOCK_SUBBLOCKS (data.block) > = blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); > @@ -335,6 +372,12 @@ find_assumption_locals_r (gimple_stmt_it > { > tree label = gimple_label_label (as_a <glabel *> (stmt)); > data->id.decl_map->put (label, label); > + if (DECL_NAME (label) && !DECL_ARTIFICIAL (label)) > + { > + if (assume_labels == NULL) > + assume_labels = BITMAP_ALLOC (NULL); > + bitmap_set_bit (assume_labels, DECL_UID (label)); > + } > break; > } > case GIMPLE_RETURN: > --- gcc/testsuite/c-c++-common/pr119537-1.c.jj 2025-03-31 > 20:31:06.299160568 +0200 > +++ gcc/testsuite/c-c++-common/pr119537-1.c 2025-03-31 20:34:24.526439291 > +0200 > @@ -0,0 +1,23 @@ > +/* PR middle-end/119537 */ > +/* { dg-do compile } */ > +/* { dg-options "-O0" } */ > + > +volatile int v; > +void *bar (void *, void *); > + > +void > +foo (bool z) > +{ > + if (z) > + goto *&&x; /* { dg-error "reference to > label 'x' defined inside of 'assume' attribute expression from outside of the > attribute" } */ > + /* { dg-message "as a possible target > of computed goto" "" { target c++ } .-1 } */ > + [[gnu::assume (({ x: v += 1; true; }))]];/* { dg-message "'x' defined > here" } */ > + /* { dg-warning "jump to label 'x'" "" > { target c++ } .-1 } */ > + /* { dg-message "enters statement > expression" "" { target c++ } .-2 } */ > + [[gnu::assume (({ y: v += 1; true; }))]];/* { dg-message "'y' defined > here" } */ > + /* { dg-warning "jump to label 'y'" "" > { target c++ } .-1 } */ > + goto *bar (&&x, &&y); /* { dg-error "reference to > label 'x' defined inside of 'assume' attribute expression from outside of the > attribute" } */ > + /* { dg-error "reference to label 'y' > defined inside of 'assume' attribute expression from outside of the > attribute" "" { target *-*-* } .-1 } */ > + /* { dg-message "as a possible target > of computed goto" "" { target c++ } .-2 } */ > + /* { dg-message "enters statement > expression" "" { target c++ } .-3 } */ > +} > --- gcc/testsuite/c-c++-common/pr119537-2.c.jj 2025-03-31 > 20:31:13.570060752 +0200 > +++ gcc/testsuite/c-c++-common/pr119537-2.c 2025-03-31 20:34:29.773367259 > +0200 > @@ -0,0 +1,23 @@ > +/* PR middle-end/119537 */ > +/* { dg-do compile } */ > +/* { dg-options "-O2" } */ > + > +volatile int v; > +void *bar (void *, void *); > + > +void > +foo (bool z) > +{ > + if (z) > + goto *&&x; /* { dg-error "reference to > label 'x' defined inside of 'assume' attribute expression from outside of the > attribute" } */ > + /* { dg-message "as a possible target > of computed goto" "" { target c++ } .-1 } */ > + [[gnu::assume (({ x: v += 1; true; }))]];/* { dg-message "'x' defined > here" } */ > + /* { dg-warning "jump to label 'x'" "" > { target c++ } .-1 } */ > + /* { dg-message "enters statement > expression" "" { target c++ } .-2 } */ > + [[gnu::assume (({ y: v += 1; true; }))]];/* { dg-message "'y' defined > here" } */ > + /* { dg-warning "jump to label 'y'" "" > { target c++ } .-1 } */ > + goto *bar (&&x, &&y); /* { dg-error "reference to > label 'x' defined inside of 'assume' attribute expression from outside of the > attribute" } */ > + /* { dg-error "reference to label 'y' > defined inside of 'assume' attribute expression from outside of the > attribute" "" { target *-*-* } .-1 } */ > + /* { dg-message "as a possible target > of computed goto" "" { target c++ } .-2 } */ > + /* { dg-message "enters statement > expression" "" { target c++ } .-3 } */ > +} > > Jakub > > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)