<div dir="ltr"><div dir="ltr"><br></div><div dir="ltr"><div dir="ltr"><br></div><div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Mar 26, 2020 at 3:12 PM Arthur O'Dwyer <<a href="mailto:arthur.j.odwyer@gmail.com" target="_blank">arthur.j.odwyer@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr">I'm not sure, but I do see that the call stack contains a call to<p style="margin:0px;font-stretch:normal;font-size:13px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures"></span></p><pre style="color:rgb(0,0,0);font-family:"Courier New",courier,monotype,monospace"><span>bool llvm::function_ref<bool (clang::Expr*&, bool)>::callback_fn<llvm::function_ref<bool (clang::Expr*&, bool)> const>(long, clang::Expr*&, bool)<br></span></pre>Notice that this is function_ref::callback_fn<T> instantiated with T=function_ref itself; i.e., we do have a function_ref to a function_ref. This is the thing I was saying can happen (in my "lamb/sheep" example) but which I thought should never happen in this codepath.<br>Here's function_ref's copy constructor:<p style="margin:0px;font-stretch:normal;font-size:13px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures"><br></span></p><p style="margin:0px;font-stretch:normal;font-size:13px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures">  template <typename Callable></span></p>
<p style="margin:0px;font-stretch:normal;font-size:13px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures">  function_ref(Callable &&callable,</span></p>
<p style="margin:0px;font-stretch:normal;font-size:13px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures">               std::enable_if_t<!std::is_same<std::remove_reference_t<Callable>,</span></p>
<p style="margin:0px;font-stretch:normal;font-size:13px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures">                                              function_ref>::value> * = nullptr)</span></p>
<p style="margin:0px;font-stretch:normal;font-size:13px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures">      : callback(callback_fn<typename std::remove_reference<Callable>::type>),</span></p>
<p style="margin:0px;font-stretch:normal;font-size:13px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures">        callable(reinterpret_cast<intptr_t>(&callable)) {}</span></p><p style="margin:0px;font-stretch:normal;font-size:13px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures"><br></span></p>I believe that it should be using std::remove_cvref_t, not std::remove_reference_t, so as not to conflict with the compiler's implicitly generated copy constructor.</div><div dir="ltr"><br>Thoughts?<br></div></div></div></blockquote><div><br></div><div>Yep, looks like you're on to something here - I still don't understand why calling that function rather than the real trivial copy ctor would be problematic, but I managed to reproduce this locally with GCC 7.5 (seems to be an issue with the 7 series - the buildbot used 7.3) & if I capture by value in both outer and inner lambdas it reproduces, but if I mark the outer lambda as mutable it succeeds (because this would remove the const & not trip over the SFINAE issue you pointed out)... <br><br>Investigation continues.<br><br>- Dave</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr">–Arthur<p style="margin:0px;font-stretch:normal;font-size:13px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures"><br></span></p></div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Mar 26, 2020 at 5:08 PM David Blaikie <<a href="mailto:dblaikie@gmail.com" target="_blank">dblaikie@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Hey Richard - could you help try to diagnose what's happening here?<br><br>I reverted this patch in: <a href="https://github.com/llvm/llvm-project/commit/0d0b90105f92f6cd9cc7004d565834f4429183fb" target="_blank">https://github.com/llvm/llvm-project/commit/0d0b90105f92f6cd9cc7004d565834f4429183fb</a><br>But that did actually cause buildbot failures, such as these ones: <a href="http://lab.llvm.org:8011/builders/clang-ppc64be-linux-multistage/builds/24491" target="_blank">http://lab.llvm.org:8011/builders/clang-ppc64be-linux-multistage/builds/24491</a><br>  eg: <a href="http://lab.llvm.org:8011/builders/clang-ppc64be-linux-multistage/builds/24491/steps/ninja%20check%201/logs/FAIL%3A%20Clang%3A%3Adeclare_variant_mixed_codegen.cpp" target="_blank">http://lab.llvm.org:8011/builders/clang-ppc64be-linux-multistage/builds/24491/steps/ninja%20check%201/logs/FAIL%3A%20Clang%3A%3Adeclare_variant_mixed_codegen.cpp</a><br>I "fixed" these failures blind by reapplying part of this original commit (the lambda capture by reference rather than by value): <a href="https://github.com/llvm/llvm-project/commit/2ec59a0a40f4ec02e6b2dbe5f12261959c191aa9" target="_blank">https://github.com/llvm/llvm-project/commit/2ec59a0a40f4ec02e6b2dbe5f12261959c191aa9</a><br><br>I've stared at this a fair bit and can't spot any undefined behavior, but I guess it's probably in there somewhere - and I'm worried that this fix is blind, not fully justified & might be hiding some latent issues.<br><br>The full buildbot example failure quoted here in case it times out/gets deleted on the buildbot itself:<br><br>******************** TEST 'Clang :: OpenMP/declare_variant_mixed_codegen.cpp' FAILED ********************<br>Script:<br>--<br>: 'RUN: at line 1';   /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang -cc1 -internal-isystem /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/lib/clang/11.0.0/include -nostdsysteminc -verify -fopenmp -x c++ -triple x86_64-unknown-linux -emit-llvm /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/llvm/clang/test/OpenMP/declare_variant_mixed_codegen.cpp -fexceptions -fcxx-exceptions -o - -fsanitize-address-use-after-scope | /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/FileCheck /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/llvm/clang/test/OpenMP/declare_variant_mixed_codegen.cpp<br>: 'RUN: at line 2';   /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang -cc1 -internal-isystem /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/lib/clang/11.0.0/include -nostdsysteminc -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-linux -fexceptions -fcxx-exceptions -emit-pch -o /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/tools/clang/test/OpenMP/Output/declare_variant_mixed_codegen.cpp.tmp -fopenmp-version=50 /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/llvm/clang/test/OpenMP/declare_variant_mixed_codegen.cpp<br>: 'RUN: at line 3';   /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang -cc1 -internal-isystem /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/lib/clang/11.0.0/include -nostdsysteminc -fopenmp -x c++ -triple x86_64-unknown-linux -fexceptions -fcxx-exceptions -std=c++11 -include-pch /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/tools/clang/test/OpenMP/Output/declare_variant_mixed_codegen.cpp.tmp -verify /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/llvm/clang/test/OpenMP/declare_variant_mixed_codegen.cpp -emit-llvm -o - -fopenmp-version=50 | /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/FileCheck /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/llvm/clang/test/OpenMP/declare_variant_mixed_codegen.cpp<br>--<br>Exit Code: 2<br><br>Command Output (stderr):<br>--<br>Stack dump:<br>0.       Program arguments: /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang -cc1 -internal-isystem /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/lib/clang/11.0.0/include -nostdsysteminc -verify -fopenmp -x c++ -triple x86_64-unknown-linux -emit-llvm /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/llvm/clang/test/OpenMP/declare_variant_mixed_codegen.cpp -fexceptions -fcxx-exceptions -o - -fsanitize-address-use-after-scope <br>1.     /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/llvm/clang/test/OpenMP/declare_variant_mixed_codegen.cpp:38:92: at annotation token<br> #0 0x0000000012e3ebd0 llvm::sys::PrintStackTrace(llvm::raw_ostream&) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x12e3ebd0)<br> #1 0x0000000012e3ece8 PrintStackTraceSignalHandler(void*) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x12e3ece8)<br> #2 0x0000000012e3c4e0 llvm::sys::RunSignalHandlers() (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x12e3c4e0)<br> #3 0x0000000012e3d3a4 SignalHandler(int) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x12e3d3a4)<br> #4 0x00007fffb50f04d8 (linux-vdso64.so.1+0x4d8)<br> #5 0x0000000014df41ac bool llvm::function_ref<bool (clang::Expr*&, bool)>::callback_fn<llvm::function_ref<bool (clang::Expr*&, bool)> const>(long, clang::Expr*&, bool) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x14df41ac)<br> #6 0x00007fffff5e7fd0 <br> #7 0x0000000014e2bfd0 clang::OMPTraitInfo::OMPTraitSelector* std::__find_if<clang::OMPTraitInfo::OMPTraitSelector*, __gnu_cxx::__ops::_Iter_pred<clang::OMPTraitInfo::anyScoreOrCondition(llvm::function_ref<bool (clang::Expr*&, bool)>)::'lambda'(clang::OMPTraitInfo::OMPTraitSet&)::operator()(clang::OMPTraitInfo::OMPTraitSet&) const::'lambda'(clang::OMPTraitInfo::OMPTraitSelector&)> >(clang::OMPTraitInfo::OMPTraitSelector*, clang::OMPTraitInfo::OMPTraitSelector*, __gnu_cxx::__ops::_Iter_pred<clang::OMPTraitInfo::anyScoreOrCondition(llvm::function_ref<bool (clang::Expr*&, bool)>)::'lambda'(clang::OMPTraitInfo::OMPTraitSet&)::operator()(clang::OMPTraitInfo::OMPTraitSet&) const::'lambda'(clang::OMPTraitInfo::OMPTraitSelector&)>, std::random_access_iterator_tag) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x14e2bfd0)<br> #8 0x0000000014e2c118 bool llvm::any_of<llvm::SmallVector<clang::OMPTraitInfo::OMPTraitSelector, 4u>&, clang::OMPTraitInfo::anyScoreOrCondition(llvm::function_ref<bool (clang::Expr*&, bool)>)::'lambda'(clang::OMPTraitInfo::OMPTraitSet&)::operator()(clang::OMPTraitInfo::OMPTraitSet&) const::'lambda'(clang::OMPTraitInfo::OMPTraitSelector&)>(llvm::SmallVector<clang::OMPTraitInfo::OMPTraitSelector, 4u>&, clang::OMPTraitInfo::anyScoreOrCondition(llvm::function_ref<bool (clang::Expr*&, bool)>)::'lambda'(clang::OMPTraitInfo::OMPTraitSet&)::operator()(clang::OMPTraitInfo::OMPTraitSet&) const::'lambda'(clang::OMPTraitInfo::OMPTraitSelector&)) (.isra.3726) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x14e2c118)<br> #9 0x0000000014e2c2a4 clang::OMPTraitInfo::OMPTraitSet* std::__find_if<clang::OMPTraitInfo::OMPTraitSet*, __gnu_cxx::__ops::_Iter_pred<clang::OMPTraitInfo::anyScoreOrCondition(llvm::function_ref<bool (clang::Expr*&, bool)>)::'lambda'(clang::OMPTraitInfo::OMPTraitSet&)> >(clang::OMPTraitInfo::OMPTraitSet*, clang::OMPTraitInfo::OMPTraitSet*, __gnu_cxx::__ops::_Iter_pred<clang::OMPTraitInfo::anyScoreOrCondition(llvm::function_ref<bool (clang::Expr*&, bool)>)::'lambda'(clang::OMPTraitInfo::OMPTraitSet&)>, std::random_access_iterator_tag) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x14e2c2a4)<br>#10 0x0000000014e2c368 bool llvm::any_of<llvm::SmallVector<clang::OMPTraitInfo::OMPTraitSet, 4u>&, clang::OMPTraitInfo::anyScoreOrCondition(llvm::function_ref<bool (clang::Expr*&, bool)>)::'lambda'(clang::OMPTraitInfo::OMPTraitSet&)>(llvm::SmallVector<clang::OMPTraitInfo::OMPTraitSet, 4u>&, clang::OMPTraitInfo::anyScoreOrCondition(llvm::function_ref<bool (clang::Expr*&, bool)>)::'lambda'(clang::OMPTraitInfo::OMPTraitSet&)) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x14e2c368)<br>#11 0x0000000014e2cc38 clang::Sema::checkOpenMPDeclareVariantFunction(clang::OpaquePtr<clang::DeclGroupRef>, clang::Expr*, clang::OMPTraitInfo&, clang::SourceRange) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x14e2cc38)<br>#12 0x00000000148fc550 clang::Parser::ParseOMPDeclareVariantClauses(clang::OpaquePtr<clang::DeclGroupRef>, llvm::SmallVector<clang::Token, 4u>&, clang::SourceLocation) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x148fc550)<br>#13 0x00000000148fd354 clang::Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(clang::AccessSpecifier&, clang::Parser::ParsedAttributesWithRange&, bool, clang::TypeSpecifierType, clang::Decl*) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x148fd354)<br>#14 0x00000000148723c4 clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange&, clang::ParsingDeclSpec*) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x148723c4)<br>#15 0x000000001487395c clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&, bool) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x1487395c)<br>#16 0x0000000014866a20 clang::ParseAST(clang::Sema&, bool, bool) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x14866a20)<br>#17 0x00000000136f6298 clang::ASTFrontendAction::ExecuteAction() (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x136f6298)<br>#18 0x0000000013de8220 clang::CodeGenAction::ExecuteAction() (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x13de8220)<br>#19 0x00000000136fcc64 clang::FrontendAction::Execute() (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x136fcc64)<br>#20 0x00000000136b71c0 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x136b71c0)<br>#21 0x00000000137c9794 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x137c9794)<br>#22 0x00000000109674cc cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x109674cc)<br>#23 0x00000000109635b8 ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&) (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x109635b8)<br>#24 0x00000000108b838c main (/home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/clang+0x108b838c)<br>#25 0x00007fffb4a55b10 generic_start_main.isra.0 (/lib64/power8/libc.so.6+0x45b10)<br>#26 0x00007fffb4a55d38 __libc_start_main (/lib64/power8/libc.so.6+0x45d38)<br>FileCheck error: '<stdin>' is empty.<br>FileCheck command line:  /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/stage1/bin/FileCheck /home/buildbots/ppc64be-clang-multistage-test/clang-ppc64be-multistage/llvm/clang/test/OpenMP/declare_variant_mixed_codegen.cpp<br><br>--<br><br>********************<br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sun, Mar 22, 2020 at 7:38 PM David Blaikie <<a href="mailto:dblaikie@gmail.com" target="_blank">dblaikie@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Reverted in 0d0b90105f92f6cd9cc7004d565834f4429183fb & I'll see what happens with the buildbots.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sun, Mar 22, 2020 at 5:47 PM Johannes Doerfert <<a href="mailto:johannes@jdoerfert.de" target="_blank">johannes@jdoerfert.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
Apologies for the confusion.<br>
<br>
I wrote the commit message after looking into this and I though the<br>
issue was related to the capture by copy in the inner llvm::any_of and<br>
the reuse in the outer. Looking back at the code I cannot say anymore<br>
how I got that impression.<br>
<br>
If you think the reference is problematic, I'm totally happy to remove<br>
it. If the windows bots (or any other ones) don't like it we need to<br>
investigate why. As mentioned, I had a problem recreating the problem<br>
locally before.<br>
<br>
Cheers,<br>
   Johannes<br>
<br>
<br>
On 3/22/20 1:37 PM, Arthur O'Dwyer wrote:<br>
 > On Sun, Mar 22, 2020 at 1:48 PM David Blaikie via cfe-commits <<br>
 > <a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>> wrote:<br>
 ><br>
 >> On Sun, Mar 22, 2020 at 10:40 AM Johannes Doerfert <br>
<<a href="mailto:johannes@jdoerfert.de" target="_blank">johannes@jdoerfert.de</a>><br>
 >> wrote:<br>
 >><br>
 >>> Some buildbots, I think only Windows buildbots for some reason, crashed<br>
 >>> in this function.<br>
 >>><br>
 >>> The reason, as described, is that an `llvm::function_ref` cannot be<br>
 >>> copied and then reused. It just happened to work on almost all<br>
 >>> configurations.<br>
 >>><br>
 >><br>
 >> That doesn't seem to be accurate, or if it is there's a lot of <br>
mistakes in<br>
 >> the codebase - basically every function_ref parameter I can see in <br>
LLVM is<br>
 >> passing by value, not by const ref. The implementation of<br>
 >> llvm::function_ref looks quite copyable so long as it doesn't <br>
outlive the<br>
 >> functor it is pointing to.<br>
 >><br>
 ><br>
 > David is correct. llvm::function_ref, like std::reference_wrapper, is a<br>
 > trivially copyable type, and it's designed to be copied.<br>
 > Like string_view and reference_wrapper, function_ref is designed to be<br>
 > passed by value. Redundantly passing function_ref *again by <br>
reference* is a<br>
 > code smell.<br>
 ><br>
 > I've also checked the code here, and it looks like there are only two<br>
 > callers of `anyScoreOrCondition` — both in Sema/SemaOpenMP.cpp — and they<br>
 > are both fine. FWIW, I would recommend reverting Johannes' change and<br>
 > seeing if those Windows buildbots are still unhappy (and if so, why).<br>
 ><br>
 ><br>
 > Btw, one failure mode I'm aware of, but which I believe is NOT <br>
relevant in<br>
 > Johannes' case, is that `function_ref`'s converting constructor behaves<br>
 > differently from its copy constructor.<br>
 ><br>
 > int main()<br>
 ><br>
 > {<br>
 ><br>
 >     auto lamb = [](){ return 42; };<br>
 ><br>
 >     auto sheep = [](){ return 43; };<br>
 ><br>
 >     llvm::function_ref<int()> one = lamb;<br>
 ><br>
 ><br>
 >     llvm::function_ref<int()> twoA = one;    // twoA refers to lamb<br>
 ><br>
 >     llvm::function_ref<short()> twoB = one;  // twoB refers to one which<br>
 > refers to lamb<br>
 ><br>
 ><br>
 >     one = sheep;<br>
 ><br>
 ><br>
 >     assert(twoA() == 42);  // twoA refers to lamb<br>
 ><br>
 >     assert(twoB() == 43);  // twoB refers to one which refers to sheep<br>
 ><br>
 > }<br>
 ><br>
 > That is, if you have a function that takes a parameter of type<br>
 > function_ref<A>, and someone passes it an argument of type <br>
function_ref<B>,<br>
 > then inside the function your parameter will be referring to that <br>
argument<br>
 > itself instead of to its referent.<br>
 > However, in Johannes' particular case, we have no function_refs referring<br>
 > to other function_refs. We just make a lambda and take a function_ref to<br>
 > it, the end. So I'm pretty sure this pitfall is irrelevant.<br>
 ><br>
 > –Arthur<br>
 ><br>
<br>
</blockquote></div>
</blockquote></div>
</blockquote></div>
</blockquote></div></div>
</div>
</div>