Bug 94970 - d: internal compiler error: in verify_gimple_stmt, at tree-cfg.c:4959
Summary: d: internal compiler error: in verify_gimple_stmt, at tree-cfg.c:4959
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: d (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: ---
Assignee: Iain Buclaw
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-05-06 09:57 UTC by Iain Buclaw
Modified: 2020-05-17 14:37 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Iain Buclaw 2020-05-06 09:57:15 UTC
Reduced test also seen on version 9.2.1.  With -fno-checking, the ICE instead happens in lower_stmt, at gimple-low.c:409.

struct RegexMatch
{   
    static @property m() { return RegexMatch(); }
    string opIndex(size_t) { return null; }
    ~this() { }
}

void initCommands()
{   
    auto a = RegexMatch.m[1] ~ ' ';
}
Comment 1 Iain Buclaw 2020-05-06 10:55:35 UTC
The statement it is balking on is GIMPLE_WITH_CLEANUP_EXPR.
Comment 2 Iain Buclaw 2020-05-06 13:00:30 UTC
Because RegexMatch needs destruction, a temporary is created that requires scope destruction.  The temporary is wrapped in a TARGET_EXPR, and dtor call set in TARGET_EXPR_CLEANUP.

  TARGET_EXPR <D.4046, tmp = m () [return slot optimization], __dtor(&tmp)>


A clean-up point is then created around the initialization of 'a'.

  <<cleanup_point a = ... >>


The problem is that for the array concat expression on the RHS, a BIND_EXPR is set-up for a temporary created for the character literal (its address needs to be taken).

The routine gimplify_cleanup_point_expr does not look any lower than the first level of sequences in the body, so it completely misses the GIMPLE_WITH_CLEANUP_EXPRs in the following:

{
  const char D.4043;

  try 
    { 
      D.4043 = 32;
      D.4110.length = 1;
      D.4110.ptr = &D.4043;
      __tmpfordtor57 = m (); [return slot optimization]
      <<< Unknown GIMPLE statement: gimple_with_cleanup_expr >>>

      <<< Unknown GIMPLE statement: gimple_with_cleanup_expr >>>

      D.4111 = index (&__tmpfordtor57);
      D.4112 = _d_arraycatT (&_D12TypeInfo_Aya6__initZ, D.4111, D.4110);
      retval.0 = VIEW_CONVERT_EXPR<struct >(D.4112);
    } 
  finally
    {
      D.4043 = {CLOBBER};
    }
}
retval.1 = retval.0;
a = retval.1;



There is a note above gimplify_cleanup_point_expr:

FIXME should we complexify the prequeue handling instead?  Or use flags
for all the cleanups and let the optimizer tighten them up?  The current
code seems pretty fragile; it will break on a cleanup within any
non-conditional nesting.  But any such nesting would be broken, anyway;
we can't write a TRY_FINALLY_EXPR that starts inside a nesting construct
and continues out of it.  We can do that at the RTL level, though, so
having an optimizer to tighten up try/finally regions would be a Good
Thing.
Comment 3 Iain Buclaw 2020-05-06 13:06:40 UTC
Somewhat simplified reduction of test that doesn't depend on operator overloading.

struct RegexMatch
{
    string index() { return null; }
    ~this() { }
}
auto m() { return RegexMatch(); }

void initCommands()
{
    auto a = m.index() ~ ' ';
}
Comment 4 Iain Buclaw 2020-05-06 13:13:57 UTC
(In reply to Iain Buclaw from comment #3)
> Somewhat simplified reduction of test that doesn't depend on operator
> overloading.
> 
> struct RegexMatch
> {
>     string index() { return null; }
>     ~this() { }
> }
> auto m() { return RegexMatch(); }
> 
> void initCommands()
> {
>     auto a = m.index() ~ ' ';
> }


There are two places that create a BIND_EXPR in the D front end, first in CatExp, the other in NewExp.

The ICE would also happen there as well, and indeed, it does if the initialization is replaced with.

    auto a = new int[](m.index);
Comment 5 GCC Commits 2020-05-06 21:57:08 UTC
The master branch has been updated by Iain Buclaw <ibuclaw@gcc.gnu.org>:

https://gcc.gnu.org/g:0af711e1914ab6d88538f1fcf0146757b5608b1d

commit r11-154-g0af711e1914ab6d88538f1fcf0146757b5608b1d
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date:   Wed May 6 23:34:11 2020 +0200

    d: Fix ICE in verify_gimple_stmt, at tree-cfg.c:4959
    
    Both array concat and array new expressions wrapped any temporaries
    created into a BIND_EXPR.  This does not work if an expression used to
    construct the result requires scope destruction, which is represented by
    a TARGET_EXPR with a clean-up, and a CLEANUP_POINT_EXPR at the
    location where the temporaries logically go out of scope.  The reason
    for this not working is because the lowering of cleanup point
    expressions does not traverse inside BIND_EXPRs to expand any gimple
    cleanup expressions within.
    
    The use of creating BIND_EXPR has been removed at both locations, and
    replaced with a normal temporary variable that has initialization
    delayed until its address is taken.
    
    gcc/d/ChangeLog:
    
            PR d/94970
            * d-codegen.cc (force_target_expr): Move create_temporary_var
            implementation inline here.
            (create_temporary_var): Remove.
            (maybe_temporary_var): Remove.
            (bind_expr): Remove.
            * d-convert.cc (d_array_convert): Use build_local_temp to generate
            temporaries, and generate its assignment.
            * d-tree.h (create_temporary_var): Remove.
            (maybe_temporary_var): Remove.
            (d_array_convert): Remove vars argument.
            * expr.cc (ExprVisitor::visit (CatExp *)): Use build_local_temp to
            generate temporaries, don't wrap them in a BIND_EXPR.
            (ExprVisitor::visit (NewExp *)): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            PR d/94970
            * gdc.dg/pr94970.d: New test.
Comment 6 GCC Commits 2020-05-17 14:26:19 UTC
The releases/gcc-10 branch has been updated by Iain Buclaw <ibuclaw@gcc.gnu.org>:

https://gcc.gnu.org/g:79f2ae6ecffbef5c1f78459f6980e0f91121022d

commit r10-8149-g79f2ae6ecffbef5c1f78459f6980e0f91121022d
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date:   Sun May 17 16:25:35 2020 +0200

    d: Fix ICE in verify_gimple_stmt, at tree-cfg.c:4959
    
    Both array concat and array new expressions wrapped any temporaries
    created into a BIND_EXPR.  This does not work if an expression used to
    construct the result requires scope destruction, which is represented by
    a TARGET_EXPR with a clean-up, and a CLEANUP_POINT_EXPR at the
    location where the temporaries logically go out of scope.  The reason
    for this not working is because the lowering of cleanup point
    expressions does not traverse inside BIND_EXPRs to expand any gimple
    cleanup expressions within.
    
    The use of creating BIND_EXPR has been removed at both locations, and
    replaced with a normal temporary variable that has initialization
    delayed until its address is taken.
    
    gcc/d/ChangeLog:
    
            PR d/94970
            * d-codegen.cc (force_target_expr): Move create_temporary_var
            implementation inline here.
            (create_temporary_var): Remove.
            (maybe_temporary_var): Remove.
            (bind_expr): Remove.
            * d-convert.cc (d_array_convert): Use build_local_temp to generate
            temporaries, and generate its assignment.
            * d-tree.h (create_temporary_var): Remove.
            (maybe_temporary_var): Remove.
            (d_array_convert): Remove vars argument.
            * expr.cc (ExprVisitor::visit (CatExp *)): Use build_local_temp to
            generate temporaries, don't wrap them in a BIND_EXPR.
            (ExprVisitor::visit (NewExp *)): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            PR d/94970
            * gdc.dg/pr94970.d: New test.
Comment 7 GCC Commits 2020-05-17 14:35:19 UTC
The releases/gcc-9 branch has been updated by Iain Buclaw <ibuclaw@gcc.gnu.org>:

https://gcc.gnu.org/g:80cefde6212c3de603dda46d05123a750b378ff2

commit r9-8601-g80cefde6212c3de603dda46d05123a750b378ff2
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date:   Sun May 17 16:28:24 2020 +0200

    d: Fix ICE in verify_gimple_stmt, at tree-cfg.c:4959
    
    Both array concat and array new expressions wrapped any temporaries
    created into a BIND_EXPR.  This does not work if an expression used to
    construct the result requires scope destruction, which is represented by
    a TARGET_EXPR with a clean-up, and a CLEANUP_POINT_EXPR at the
    location where the temporaries logically go out of scope.  The reason
    for this not working is because the lowering of cleanup point
    expressions does not traverse inside BIND_EXPRs to expand any gimple
    cleanup expressions within.
    
    The use of creating BIND_EXPR has been removed at both locations, and
    replaced with a normal temporary variable that has initialization
    delayed until its address is taken.
    
    gcc/d/ChangeLog:
    
            PR d/94970
            * d-codegen.cc (force_target_expr): Move create_temporary_var
            implementation inline here.
            (create_temporary_var): Remove.
            (maybe_temporary_var): Remove.
            (bind_expr): Remove.
            * d-convert.cc (d_array_convert): Use build_local_temp to generate
            temporaries, and generate its assignment.
            * d-tree.h (create_temporary_var): Remove.
            (maybe_temporary_var): Remove.
            (d_array_convert): Remove vars argument.
            * expr.cc (ExprVisitor::visit (CatExp *)): Use build_local_temp to
            generate temporaries, don't wrap them in a BIND_EXPR.
            (ExprVisitor::visit (NewExp *)): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            PR d/94970
            * gdc.dg/pr94970.d: New test.
Comment 8 Iain Buclaw 2020-05-17 14:37:19 UTC
Fixed and backported.