On Thu, Mar 26, 2020 at 11:49 PM Richard Smith <rich...@metafoo.co.uk>
wrote:

> On Thu, 26 Mar 2020 at 17:07, David Blaikie via cfe-commits <
> cfe-commits@lists.llvm.org> wrote:
>
>> On Thu, Mar 26, 2020 at 3:12 PM Arthur O'Dwyer <arthur.j.odw...@gmail.com>
>> wrote:
>>
>>> I'm not sure, but I do see that the call stack contains a call to
>>>
>>> bool llvm::function_ref<bool (clang::Expr*&, 
>>> bool)>::callback_fn<llvm::function_ref<bool (clang::Expr*&, bool)> 
>>> const>(long, clang::Expr*&, bool)
>>>
>>> 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.
>>> Here's function_ref's copy constructor:
>>>
>>>
>>>   template <typename Callable>
>>>
>>>   function_ref(Callable &&callable,
>>>
>>>
>>> std::enable_if_t<!std::is_same<std::remove_reference_t<Callable>,
>>>
>>>                                               function_ref>::value> * =
>>> nullptr)
>>>
>>>       : callback(callback_fn<typename
>>> std::remove_reference<Callable>::type>),
>>>
>>>         callable(reinterpret_cast<intptr_t>(&callable)) {}
>>>
>>>
>>> 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.
>>>
>>> Thoughts? [...]
>>>
>>
> OK, so: we're calling the wrong constructor for the inner capture due to
> the implicit 'const' that's added because the outer lambda is not mutable
> (and the fix suggested by Arthur is the right one: we should be using
> remove_cvref_t here not remove_reference_t -- or rather
> std::remove_cv_t<std::remove_reference_t<Callable>>, since we don't require
> C++20 yet). And this means that copying a function_ref from a *const*
> function_ref gives you a new function_ref that refers to the old one, not a
> new function_ref that refers to the same function the old one did.
>

Argh! That is insanely sneaky, and it is quite probable IMHO that this is a
core-language bug in GCC, because GCC behaves differently from EDG and
Clang here.
https://godbolt.org/z/oCvLpv
On GCC, when you have a lambda nested within a lambda, and you
capture-by-copy a variable which was captured-by-copy using [=] or [i] (but
not C++14 init-capture [i=i]), then your data member for that capture will
have type `const I`, not just `I`.
On Clang and EDG, [=], [i], and [i=i] all behave equivalently, and capture
a data member with type `I`.

I don't see anything about this on
https://gcc.gnu.org/bugzilla/buglist.cgi?quicksearch=lambda%20capture%20const
— Richard, you might be best able to describe the issue correctly ;) but if
you want me to file it, I will.  (Might be a corollary of bug 86697
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86697>.)

Regardless, llvm::function_ref's SFINAE should still be fixed. This is a
bug in llvm::function_ref, exposed by a bug in GCC. (Or vice versa.)

–Arthur
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to