<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/140009>140009</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Clang emits llvm.memcpy for closure type without lambda-capature in C++20 but not in C++17
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            clang:codegen
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          MaskRay
      </td>
    </tr>
</table>

<pre>
    In C++20, a closure type without lambda-capture has a defaulted default constructor, different from previous versions of standards.
https://eel.is/c++draft/expr.prim.lambda#capture

> The closure type associated with a lambda-expression has no default constructor if the lambda-expression has a lambda-capture and a defaulted default constructor otherwise.

This leads to a redundant `memcpy` call for the following C++ code: https://godbolt.org/z/9xbM5fj5W

```cpp
#define F(a, b) { \
 auto check = [](const char *, long) {}; \
    check(a, b); \
    asm("// %0 %1" : : "r"(a), "r"(b)); }

void foo() { F("hello", 3); }
```

```llvm
// -std=c++17 -O0
%class.anon = type { i8 }

@.str = private unnamed_addr constant [6 x i8] c"hello\00", align 1

define dso_local void @foo()() #0 {
  %1 = alloca %class.anon, align 1
  call void @"foo()::$_0::operator()(char const*, long) const"(ptr noundef nonnull align 1 dereferenceable(1) %1, ptr noundef @.str, i64 noundef 3)
  call void asm sideeffect "// $0 $1", "r,r,~{dirflag},~{fpsr},~{flags}"(ptr @.str, i32 3) #2
  ret void
}

// -std=c++20 -O0
%class.anon = type { i8 }

@__const.foo().check = private unnamed_addr constant %class.anon undef, align 1
@.str = private unnamed_addr constant [6 x i8] c"hello\00", align 1

define dso_local void @foo()() #0 {
  %1 = alloca %class.anon, align 1
  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %1, ptr align 1 @__const.foo().check, i64 1, i1 false)
  call void @"foo()::$_0::operator()(char const*, long) const"(ptr noundef nonnull align 1 dereferenceable(1) %1, ptr noundef @.str, i64 noundef 3)
  call void asm sideeffect "// $0 $1", "r,r,~{dirflag},~{fpsr},~{flags}"(ptr @.str, i32 3) #3
  ret void
}
```

In -O0, the `memcpy` is retained, and leads to something like `movb .L__const.foo().check(%rip), %al` on x86-64.

A redundant capture `auto check = [x=a](const char *, long) {};` suppresses the `llvm.memcpy` intrinsic (but introduces a useless `const char*` store).
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzsVluL47gS_jXKS9FGkW_xQx7SyQkMnOHAYeA8NrJUjjUjS0aSM93nYX_7Itm59Uwzu7BPy4LTHVdcl--rT67i3quTQdyS8pmUhxWfQm_d9jP33_7L31atlW_bTwb2hD0T9swoYXvgILT1k0MIbyPCdxV6OwXQfGglfxJ8DPG3nnvgILHjkw4oL99AWOODm0SwLgaTquvQoQnQOTvA6PCs7OThjM4razzYDnzgRnInfUborg9h9CTfEXYk7IioM-UJO4q5Qul4F6L9dXTZ6NSQzWURli-FEbqLV_4v-NLjIxLuvRWKx2ojKOAXTDEa-lhPgmXsz9CA6iD0-IEPf88PN_JX_IANPbrvymM2V_2lVx40cukhWODgUE5GchOAVHTAQYxvpKIguNbQWZfK6azW9rsyp0sTQViJJN_BI5MnK1urQ2bdibDj_wk7Nq_t57L7Wv5voayi8yXGMd6yXGKnDMKRsA2PvWwJa4DUz0DKPaE74FOwIHoU34DkB5glRtgmQQTRcweE7aKntua0OJP6QPJrCIA5wH2Kx5-5HwjbEMZmGEBYSeOfNWEMIsz0YcylR2KUJga6WVLIJWp9mLGerZLQWZsiz5iOc5YetbbJcQ_5o9uFn3d0aX0eEl-pvCcfJMkPi1zXNTz9JzmwUmjufcaNNYmtpMiYWG1udZGCZj649MDo1JkHhMkYPqB84VK6WT1JEOVzBa-gNqQ8gLgWXu4pXarnWp0MrOfASyulty_aCq4hMUAKeiXhQgXLaWpTZD_SnGrhOnrBA4rHHDCr8hKWMHaLnO-SCosXOn-1Izqe3g9L4iSVBO2dXhZbbOMYHBg7GYkdGGvMpPUlPUh0mN4yAnmrkbDNesYSVbKHe9eF4WhWVXE1p1Y_ouB-AK8kYtehCHCvwCIqsFgvRM9S28fPb6R-lsp1mp9iT2dDN3p3d6f5yafbC6r7knKWSoltYKkehyGVE9t4VcnPpMbon5bay0viN7t2Krsd5l-o7yFHovCd5P4uQo6nO5tfvdlI46WqYmncRX73OrvaPqT3Ir3kotbQce3xR_n9c4j-ikOUf3CIHt_ln0w6O2yfJurDrFU-enNlUCadGHkb0N4OGPo4erX6NvvZcwvZvz_s_Iaw0qnxOqNKrmMSa-B1Uz1VxbIH7O4m_2WfIBX9cd6-kvzA__DQjan8NKa9Bf0F653CE2ATnDJeCYizcwrJYOUkMC45k0eN3ke_W8KYL4YO1kUhZyu5zWWTN3yF23Vd1KyhzbpY9VtBG543RdFIzGlXCyHrXFSsbcq2rsuiXakto6yk5bqkVV6ui6zKK9E0gudNXTNW1KSgOHCls1S1daeV8n7C7bqglDYrzVvUPi27jAnNzYnku7gPndBErZSHldtG16d2Ovl4vJUP_hYsqKBxu4-OgIMKHu7YSSvXL1Zjnnql7jZqiBwaG-6M63o1Ob19t5-p0E9tJuxA2DHtFPO_p9HZryji0pugxmV4QXvest8DAAD__8Ffirw">