<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Jan 28, 2015 at 2:11 PM, Ben Langmuir <span dir="ltr"><<a href="mailto:blangmuir@apple.com" target="_blank">blangmuir@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><br><div><span><blockquote type="cite"><div>On Jan 28, 2015, at 1:21 PM, Richard Smith <<a href="mailto:richard@metafoo.co.uk" target="_blank">richard@metafoo.co.uk</a>> wrote:</div><br><div><div dir="ltr">Hi Ben,<br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Jan 27, 2015 at 3:06 PM, Ben Langmuir <span dir="ltr"><<a href="mailto:blangmuir@apple.com" target="_blank">blangmuir@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Richard,<br>
<br>
Could you take a look at this patch?  I haven’t messed with capturing in a long time and I don’t want to break it ;-)</blockquote><div> </div><div>LGTM as a diagnostics improvement (but see below).</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
    Don't mistakenly capture byref in block nested in lambda<br>
<br>
    Even if an enclosing lambda captures a variable by reference, we capture<br>
    it by *copy* in a block unless the variable itself was declared with a<br>
    reference type. Codegen was already correct, but we were not diagnosing<br>
    attempts to modify the variable in Sema.<br></blockquote><div><br></div><div>Hmm, I think I'm missing something here</div></div></div></div></div></blockquote></span></div></div></blockquote><div>D'oh, what I was missing was the change to captureInBlock!</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><span><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>-- it looks like we would diagnose it, but we'd use a suboptimal diagnostic: CheckForModifiableLvalue would diagnose as err_typecheck_assign_const in this case.</div></div></div></div></div></blockquote><div><br></div></span><div>It wouldn’t be const at all, because we created the (bogus) byref capture.  It occurs to me that my tests don’t make this obvious, so I’ll add:</div><div><br></div><div>int x = 0;</div><div>[&]() {</div><div>  ^{</div><div>    x = 1; // this diagnoses now, but didn’t before</div><div>   }();</div><div>}();</div></div></div></blockquote><div><br></div><div>This part doesn't seem like an obviously-correct change to me. Consider the desugaring of the lambda:</div><div><br></div><div>struct Lambda {</div><div>  int &x;</div><div>  Lambda(int &x) : x(x) {}</div><div>  auto operator()() const {</div><div>    ^{</div><div>    x = 1;</div><div>    }();</div><div>  }</div><div>};</div><div>Lambda(x)();</div><div><br></div><div>In this world, the block is referring to an entity with reference type, so it should capture by reference instead of by value. As far as I can see, there's no other way of observing this difference, so we don't have a lot of guidance here, but treating 'x' like a variable of reference type seems more consistent here. Especially when you consider:</div><div><br></div><div>[&x = x]() {</div><div>  ^{</div><div>  x = 1; // obviously ok, x obviously has reference type</div><div>  }();</div><div>}();</div><div><br></div><div>There are some strong proponents of the idea that [&x] should be exactly equivalent to [&x = x], and that [x] should be exactly equivalent to [x = x]; they *very nearly* are equivalent (they only differ in cv-qualifiers today); this change gets us further from that position.</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><span><blockquote type="cite"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
    This also fixes a crash on invalid when trying to modify a variable with<br>
    non-trivial copy constructor and assignment operator in such a<br>
    situation.<br></blockquote><div><br></div><div>I can't reproduce this crash with current trunk, assuming this is supposed to be covered by the uses of 'A' in test7 in SemaCXX/blocks.cpp.</div></div></div></div>
</blockquote></span></div><br><div>Ah my mistake, the crash was reading from the value, not writing to it.  I’ll remove that ‘A’ case in the Sema test and add an IRGen test to exercise it.  If you want to reproduce it:</div><div><br></div><div>$ cat red.cpp</div><div>struct A {<br>  A() = default;<br>  A(const A &); // non-trivial copy<br>  A &operator=(const A &); // non-trivial assign<br>};<br><br>void test() {<br>  A a;<br>  [&]() { ^{ (void)a; }(); }();<br>}</div><div><br></div><div>$ clang++ -std=c++11 -fblocks red.cpp </div></div></blockquote></div><br></div><div class="gmail_extra">Given the above, maybe this is an IRGen bug?</div></div>