https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123597
--- Comment #13 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
The bug is in all the BIND_EXPR optimizations that commit added.
I mean
/* Remove redundant BIND_EXPRs with no bindings even when not specifically
trying to flatten. */
else if (TREE_CODE (*tp) == BIND_EXPR
&& BIND_EXPR_BODY (*tp) == sit->orig
&& !BIND_EXPR_VARS (*tp)
&& (sit->flatten || TREE_CODE (sit->repl) == BIND_EXPR))
and
else if (sit->flatten
&& TREE_CODE (*tp) == BIND_EXPR
&& TREE_CODE (sit->repl) == BIND_EXPR)
in substitute_in_tree_walker and
if (TREE_CODE (repl) == BIND_EXPR && !BIND_EXPR_VARS (repl))
repl = BIND_EXPR_BODY (repl);
in substitute_in_tree.
BIND_EXPRs in the FE are usually created by do_poplevel:
if (!processing_template_decl)
{
stmt_list = c_build_bind_expr (input_location, block, stmt_list);
/* ??? See c_end_compound_stmt re statement expressions. */
}
and by poplevel:
/* If this is a temporary binding created for a cleanup, then we'll
have pushed a statement list level. Pop that, create a new
BIND_EXPR for the block, and insert it into the stream. */
stmt = pop_stmt_list (current_binding_level->statement_list);
stmt = c_build_bind_expr (input_location, block, stmt);
where c_build_bind_expr doesn't always force a BIND_EXPR, but creates it only
when
needed:
if (decls || block)
{
bind = build3 (BIND_EXPR, void_type_node, decls, body, block);
TREE_SIDE_EFFECTS (bind) = 1;
SET_EXPR_LOCATION (bind, loc);
}
else
bind = body;
In do_poplevel it is clearly never called for processing_template_decl and in
poplevel
I think it isn't either, because maybe_push_cleanup_level I think is never
called for processing_template_decl, so there are no sk_cleanup scopes.
And then there is in begin_compound_stmt
/* When processing a template, we need to remember where the braces were,
so that we can set up identical scopes when instantiating the template
later. BIND_EXPR is a handy candidate for this.
Note that do_poplevel won't create a BIND_EXPR itself here (and thus
result in nested BIND_EXPRs), since we don't build BLOCK nodes when
processing templates. */
if (processing_template_decl)
{
r = build3 (BIND_EXPR, NULL, NULL, r, NULL);
BIND_EXPR_TRY_BLOCK (r) = (flags & BCS_TRY_BLOCK) != 0;
BIND_EXPR_BODY_BLOCK (r) = (flags & BCS_FN_BODY) != 0;
TREE_SIDE_EFFECTS (r) = 1;
}
So, BIND_EXPRs are created in templates for a different reason to
non-templates, and
BIND_EXPRs in templates will I think always have BIND_EXPR_VARS NULL.