public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/102065] New: [C++20] Substitution failure of function instantiates its argument
@ 2021-08-25 13:36 seredinyegor at gmail dot com
  2021-08-25 14:44 ` [Bug c++/102065] " ppalka at gcc dot gnu.org
  2021-08-25 18:00 ` seredinyegor at gmail dot com
  0 siblings, 2 replies; 3+ messages in thread
From: seredinyegor at gmail dot com @ 2021-08-25 13:36 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102065

            Bug ID: 102065
           Summary: [C++20] Substitution failure of function instantiates
                    its argument
           Product: gcc
           Version: 11.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: seredinyegor at gmail dot com
  Target Milestone: ---

Created attachment 51356
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=51356&action=edit
preprocessed file

Problem can be reproduced with:
- gcc version 11.2.0 (Ubuntu 11.2.0-1ubuntu2)
- gcc version 12.0.0 20210825 (experimental) (GCC)

Problem doesn't exist in:
- gcc version 10.3.0 (Ubuntu 10.3.0-1ubuntu1~20.04)
- Ubuntu clang version
13.0.0-++20210823084033+1f0b043ae709-1~exp1~20210823184829.58

CXXFLAGS: -std=c++20

Code:
#include <functional>

void elem_func(int) {}

template <
    typename Sequence,
    std::invocable<int> SequenceHandler
>
void func(
    const Sequence& values,
    SequenceHandler&& handler,
    std::enable_if_t<std::is_pointer_v<Sequence>, int> = 0)
{
}

template <
    typename T,
    std::invocable<T> ValueHandler
>
void func(
    T value,
    ValueHandler&& handler,
    std::enable_if_t<!std::is_pointer_v<T>, int> = 0)
{
}

int main()
{
    func(
        new int[1], // pointer => 1st func should be called 
        [](auto e)  // lambda should be std::invocable<int> => decltype(e)==int
        {
            elem_func(e); // cannot call elem_func if decltype(e)==int* (2nd
func)
        }
    );
}

Compiler output:

sfinae_bug.cpp: In instantiation of ‘main()::<lambda(auto:3)> [with auto:3 =
int*]’:
/usr/include/c++/11/type_traits:2466:26:   required by substitution of
‘template<class _Fn, class ... _Args> static std::__result_of_success<decltype
(declval<_Fn>()((declval<_Args>)()...)), std::__invoke_other>
std::__result_of_other_impl::_S_test(int) [with _Fn = main()::<lambda(auto:3)>;
_Args = {int*}]’
/usr/include/c++/11/type_traits:2477:55:   required from ‘struct
std::__result_of_impl<false, false, main()::<lambda(auto:3)>, int*>’
/usr/include/c++/11/type_traits:2937:12:   recursively required by substitution
of ‘template<class _Result, class _Ret> struct
std::__is_invocable_impl<_Result, _Ret, true, std::__void_t<typename
_CTp::type> > [with _Result = std::__invoke_result<main()::<lambda(auto:3)>,
int*>; _Ret = void]’
/usr/include/c++/11/type_traits:2937:12:   required from ‘struct
std::is_invocable<main()::<lambda(auto:3)>, int*>’
/usr/include/c++/11/type_traits:3001:73:   required from ‘constexpr const bool
std::is_invocable_v<main()::<lambda(auto:3)>, int*>’
/usr/include/c++/11/concepts:338:25:   required by substitution of
‘template<class T, class ValueHandler>  requires  invocable<ValueHandler, T>
void func(T, ValueHandler&&, std::enable_if_t<(! is_pointer_v<T>), int>) [with
T = int*; ValueHandler = main()::<lambda(auto:3)>]’
sfinae_bug.cpp:29:9:   required from here
sfinae_bug.cpp:33:23: error: invalid conversion from ‘int*’ to ‘int’
[-fpermissive]
   33 |             elem_func(e); // cannot call elem_func if decltype(e)==int*
(2nd func)
      |                       ^
      |                       |
      |                       int*

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [Bug c++/102065] [C++20] Substitution failure of function instantiates its argument
  2021-08-25 13:36 [Bug c++/102065] New: [C++20] Substitution failure of function instantiates its argument seredinyegor at gmail dot com
@ 2021-08-25 14:44 ` ppalka at gcc dot gnu.org
  2021-08-25 18:00 ` seredinyegor at gmail dot com
  1 sibling, 0 replies; 3+ messages in thread
From: ppalka at gcc dot gnu.org @ 2021-08-25 14:44 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102065

Patrick Palka <ppalka at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|---                         |DUPLICATE
                 CC|                            |ppalka at gcc dot gnu.org
             Status|UNCONFIRMED                 |RESOLVED

--- Comment #1 from Patrick Palka <ppalka at gcc dot gnu.org> ---
Thanks for the bug report!  Looks like this apparent regression started with
r11-2774 (which implements the changes in wg21.link/cwg2369).

But I think GCC's behavior is correct here, according to the latest standard. 
The associated constraints of a function template are checked immediately after
deducing all template arguments, rather than after substituting the deduced
template arguments into the function type, so your use of enable_if_t as a
function parameter doesn't actually prevent the std::invocable constraint from
getting checked (and for the hard error to occur when this constraint check
causes the body of the lambda to get instantiated with int*).

One work around in your case is to give the lambda a non-deduced return type of
'void' so that we don't need to instantiate the body of the lambda during the
std::invocable check:

        [](auto e) -> void
        {
            elem_func(e);
        }

Another more general workaround is to instead encode the enable_if_t test as an
additional constraint that guards the std::invocable constraint, something
like:

#include <functional>

void elem_func(int) {}

template <
    typename Sequence,
    typename SequenceHandler
>
  requires std::is_pointer_v<Sequence> && std::invocable<SequenceHandler, int>
void func(
    const Sequence& values,
    SequenceHandler&& handler)
{
}

template <
    typename T,
    typename ValueHandler
>
  requires (!std::is_pointer_v<T>) && std::invocable<ValueHandler, T>
void func(
    T value,
    ValueHandler&& handler)
{
}

int main()
{
    func(
        new int[1], // pointer => 1st func should be called 
        [](auto e)  // lambda should be std::invocable<int> => decltype(e)==int
        {
            elem_func(e); // cannot call elem_func if decltype(e)==int* (2nd
func)
        }
    );
}

*** This bug has been marked as a duplicate of bug 99599 ***

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [Bug c++/102065] [C++20] Substitution failure of function instantiates its argument
  2021-08-25 13:36 [Bug c++/102065] New: [C++20] Substitution failure of function instantiates its argument seredinyegor at gmail dot com
  2021-08-25 14:44 ` [Bug c++/102065] " ppalka at gcc dot gnu.org
@ 2021-08-25 18:00 ` seredinyegor at gmail dot com
  1 sibling, 0 replies; 3+ messages in thread
From: seredinyegor at gmail dot com @ 2021-08-25 18:00 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102065

--- Comment #2 from Egor Seredin <seredinyegor at gmail dot com> ---
Thank you! I agree that it is a duplicate.
Also, there is 3rd workaround without guards (may be with implicit guards):
move last function argument to last template argument:
https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAM1QDsCBlZAQwBtMQBGAFlJvoCqAZ0wAFAB4gA5AAYppAFZdSrZrVDIApACYAQjt2kR7ZATx1KmWugDCqVgFcAtrRDbOpK%2BgAyeWpgA5ZwAjTGIuAA5SAAdUIUJzWjtHFzcPWPizOl9/IKdQ8M4o40xTRIYCZmICZOdXdyNMEyzaCqqCHMCQsMijSura1Iahfo6/LvyeooBKI1QHYmQOKR0AZj9kRywAak1VmyoHWjK6Nj3sTRkAQUurgDdUPHRtpswnAH1D44g/AmndgDs%2BgBABFbrcCG9oqpIbt9rdtojtgQAJ7RKzMJyYbYMTAARwcViWpARSJG6BAID8DxYwXYexsv3OOPxhOOmAAEmp0OwyKTEaj0bRMdi9iDtuTKRi6Zh3ngqO8CAzJVShO9Yr8wu87gzcQSiZhzqRtkzVhdrudbg8ntsvsgIPztmhaCMWfr2ToAGzbO5sQlCEnXJFutlLLnWXler3bBDc3nTcFAxNgi3XSFOaHMWEMx2CjFY7YAFUDV2DKupqFp9P2heZADU/Zy42ES8G88KC2KJQQKSBpew5QqlfswGBy2qNfQtTqa0aTfRLRazVbHs87Q6g0jCz7G62kQ3HE2I2Eo9pvbHj8QExakzeUzdrr9tk5mH4INebrfS0j147g/4AHd5yVABWXROE0ECQWNAB6GDtknSFiDhMEzW2ThXTtCUEHmVhnlCJ02HYZ4/yRSD9CgiBmAcIgXn%2BbY4O2VR8nQZhsNw/DsXLWgaWYGUGVNbAUOZLBNjzCBMATVZUJBJlN2DRFNC/BSVJedgPnXSS9l0Bj4JYWhaFQAhCNYVg1LeT4jmQE0qG2UTWHErTpLFX4ACptggbRrFtKyP1UwF72DKT9DvKRZlYaQQPkVxZHkVBpBsAwDAleZFlFbRVk4eQCGkORplmABrEBVlWAA6EqKsqqrPRUaRuGi3K4ukeQhBAGRSBy2LZjgWAkDQDM8F5chKH66JBp6YAhGFaIhBwgg%2BEGpDWogYJGtIYI/CqFFpCy0h%2BqxegAHlaFYbbYtILAX3Udg1vwYhSjMO5MFa87MHEUoaOWXbNQi87WDwYJiC2uwsDWghiDwJwdrCvhVEmus8EwADDqFaG%2BDoRgWBunh0cEEQJDWpQPFUdQUCSvQVAB1rIFmVBohaF6AFpyTFLQ9AMbQ5EaZpEksaxBlcDwvE6PICmUDIEjoAXxbiSXaBF7pCm5h7ylGaWPBKE5WlGBXJiVkZ2nVvp2l1sXOFmIRUqWLhwsihrzviqRxAiT1Gc9bhtmAZBrIgcGjgK/4IES9mKe2XBCBIXYMo8bY7AG3ko8y6Zssa/LSAQTBmCwcJ31IIqSvKqqi5Kmrfvq0gYq5x2WrajrU9IHrEBAeYCGiGjhogUbxqVzB8CIJX%2BExtgOBxwfhDESRzoAoHomh22pCiiu1sdw6aLb4zUFs53Xfdz3vY8v3aADjy47GhO1nNlOusK4qyuL4vaqkcvK6aqQa/azq8vn7R7ar5q6%2BvqQJ6xB4gWG4EAA

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-08-25 18:00 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-25 13:36 [Bug c++/102065] New: [C++20] Substitution failure of function instantiates its argument seredinyegor at gmail dot com
2021-08-25 14:44 ` [Bug c++/102065] " ppalka at gcc dot gnu.org
2021-08-25 18:00 ` seredinyegor at gmail dot com

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).