On Mon, Oct 27, 2025 at 4:22 PM Anna (navi) Figueiredo Gomes
<[email protected]> wrote:
>
> represent the start and end of scope which a local jump is not allowed
> to cross as a jump barrier, moving this logic out into a function allows
> for defer statements to use the same codepath
>
> gcc/c/ChangeLog:
>
> * c-decl.cc (struct c_jump_barrier): New structure.
> (struct c_spot_bindings): Adjust.
> (set_spot_bindings): Likewise.
> (c_binding_adjust_jump_barrier): New function.
> (c_bindings_start_stmt_expr): Adjust.
> (c_bindings_end_stmt_expr): Likewise.
> (lookup_label_for_goto): Likewise.
> (check_earlier_gotos): Likewise.
> (c_release_switch_bindings): Likewise.
> (c_check_switch_jump_warnings): Likewise.
>
> Signed-off-by: Anna (navi) Figueiredo Gomes <[email protected]>
> ---
> gcc/c/c-decl.cc | 72 +++++++++++++++++++++++++------------------------
> 1 file changed, 37 insertions(+), 35 deletions(-)
>
> diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> index 7850365f35c..56ca3078226 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -379,6 +379,16 @@ c_tree_size (enum tree_code code)
> scopes are popped, we update these structures and gather the decls
> that matter at that time. */
>
> +struct GTY(()) c_jump_barrier {
> + /* The number of barriers that have started since this label or goto
> + statement was defined. This is zero if we are at the same barrier.
> + It is positive if we are in a barrier that started since this spot.
> + If it goes negative, it is reset to zero and .left is set to true. */
> + int count;
> + /* Whether we started in a barrier but are no longer in it. */
> + bool left;
> +};
> +
> struct GTY(()) c_spot_bindings {
> /* The currently open scope which holds bindings defined when the
> label was defined or the goto statement was found. */
> @@ -387,16 +397,7 @@ struct GTY(()) c_spot_bindings {
> of the label or goto. This lets us look at older or newer
> bindings in the scope, as appropriate. */
> struct c_binding *bindings_in_scope;
> - /* The number of statement expressions that have started since this
> - label or goto statement was defined. This is zero if we are at
> - the same statement expression level. It is positive if we are in
> - a statement expression started since this spot. It is negative
> - if this spot was in a statement expression and we have left
> - it. */
> - int stmt_exprs;
> - /* Whether we started in a statement expression but are no longer in
> - it. This is set to true if stmt_exprs ever goes negative. */
> - bool left_stmt_expr;
> + struct c_jump_barrier stmt_exprs;
Remove the struct tag marking, this is C++ code. I just noticed the
struct tag marking is still in the file. I think most other parts of
GCC had it removed which is why I mentioned it here. I think keeping
it here is fine as that is how the rest of the file looks.
> };
>
> /* This structure is used to keep track of bindings seen when a goto
> @@ -983,8 +984,8 @@ set_spot_bindings (struct c_spot_bindings *p, bool
> defining)
> p->scope = NULL;
> p->bindings_in_scope = NULL;
> }
> - p->stmt_exprs = 0;
> - p->left_stmt_expr = false;
> + p->stmt_exprs.count = 0;
> + p->stmt_exprs.left = false;
> }
>
> /* Update spot bindings P as we pop out of SCOPE. Return true if we
> @@ -1603,6 +1604,18 @@ finish_underspecified_init (tree name, unsigned int
> prev_state)
>
> /* Adjust the bindings for the start of a statement expression. */
>
> +static void
> +c_binding_adjust_jump_barrier (struct c_spot_bindings *binding, bool start)
Also the comment above was originally for c_bindings_start_stmt_expr
but now there is no comment above c_bindings_start_stmt_expr.
Comments before the function should describe what the function does
and what the arguments mean.
> +{
> + struct c_jump_barrier *barrier = &binding->stmt_exprs;
> + barrier->count += start ? 1 : -1;
I find the above style odd and hard to understand; It is hard to
figure count is incrementing by 1 when start is true; otherwise
decrementing by one.
Maybe this is better:
if (start)
barrier->count++;
else
barrier->count--;
Thanks,
Andrew
> + if (barrier->count < 0)
> + {
> + barrier->count = 0;
> + barrier->left = true;
> + }
> +}
> +
> void
> c_bindings_start_stmt_expr (struct c_spot_bindings* switch_bindings)
> {
> @@ -1624,14 +1637,15 @@ c_bindings_start_stmt_expr (struct c_spot_bindings*
> switch_bindings)
> if (TREE_CODE (b->decl) != LABEL_DECL)
> continue;
> label_vars = b->u.label;
> - ++label_vars->label_bindings.stmt_exprs;
> +
> + c_binding_adjust_jump_barrier (&label_vars->label_bindings, true);
> FOR_EACH_VEC_SAFE_ELT (label_vars->gotos, ix, g)
> - ++g->goto_bindings.stmt_exprs;
> + c_binding_adjust_jump_barrier (&g->goto_bindings, true);
> }
> }
>
> if (switch_bindings != NULL)
> - ++switch_bindings->stmt_exprs;
> + c_binding_adjust_jump_barrier (switch_bindings, true);
> }
>
> /* Adjust the bindings for the end of a statement expression. */
> @@ -1657,28 +1671,16 @@ c_bindings_end_stmt_expr (struct c_spot_bindings
> *switch_bindings)
> if (TREE_CODE (b->decl) != LABEL_DECL)
> continue;
> label_vars = b->u.label;
> - --label_vars->label_bindings.stmt_exprs;
> - if (label_vars->label_bindings.stmt_exprs < 0)
> - {
> - label_vars->label_bindings.left_stmt_expr = true;
> - label_vars->label_bindings.stmt_exprs = 0;
> - }
> + c_binding_adjust_jump_barrier (&label_vars->label_bindings, false);
> FOR_EACH_VEC_SAFE_ELT (label_vars->gotos, ix, g)
> - {
> - --g->goto_bindings.stmt_exprs;
> - if (g->goto_bindings.stmt_exprs < 0)
> - {
> - g->goto_bindings.left_stmt_expr = true;
> - g->goto_bindings.stmt_exprs = 0;
> - }
> - }
> + c_binding_adjust_jump_barrier (&g->goto_bindings, false);
> }
> }
>
> if (switch_bindings != NULL)
> {
> - --switch_bindings->stmt_exprs;
> - gcc_assert (switch_bindings->stmt_exprs >= 0);
> + c_binding_adjust_jump_barrier (switch_bindings, defer, false);
> + gcc_assert (switch_bindings->stmt_exprs.count >= 0);
> }
> }
>
> @@ -4149,7 +4151,7 @@ lookup_label_for_goto (location_t loc, tree name)
> FOR_EACH_VEC_SAFE_ELT (label_vars->decls_in_scope, ix, decl)
> warn_about_goto (loc, label, decl);
>
> - if (label_vars->label_bindings.left_stmt_expr)
> + if (label_vars->label_bindings.stmt_exprs.left)
> {
> auto_diagnostic_group d;
> error_at (loc, "jump into statement expression");
> @@ -4240,7 +4242,7 @@ check_earlier_gotos (tree label, struct c_label_vars*
> label_vars)
> }
> }
>
> - if (g->goto_bindings.stmt_exprs > 0)
> + if (g->goto_bindings.stmt_exprs.count > 0)
> {
> auto_diagnostic_group d;
> error_at (g->loc, "jump into statement expression");
> @@ -4331,7 +4333,7 @@ c_get_switch_bindings (void)
> void
> c_release_switch_bindings (struct c_spot_bindings *bindings)
> {
> - gcc_assert (bindings->stmt_exprs == 0 && !bindings->left_stmt_expr);
> + gcc_assert (bindings->stmt_exprs.count == 0 && !bindings->stmt_exprs.left);
> XDELETE (bindings);
> }
>
> @@ -4395,7 +4397,7 @@ c_check_switch_jump_warnings (struct c_spot_bindings
> *switch_bindings,
> }
> }
>
> - if (switch_bindings->stmt_exprs > 0)
> + if (switch_bindings->stmt_exprs.count > 0)
> {
> saw_error = true;
> auto_diagnostic_group d;
> --
> 2.51.0
>