public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/110853] New: [c++-concepts] Bad interaction between deduction guide with decay and constraints
@ 2023-07-30 14:05 daniel.kruegler at googlemail dot com
  2023-08-07 14:08 ` [Bug libstdc++/110853] " ppalka at gcc dot gnu.org
  0 siblings, 1 reply; 2+ messages in thread
From: daniel.kruegler at googlemail dot com @ 2023-07-30 14:05 UTC (permalink / raw)
  To: gcc-bugs

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

            Bug ID: 110853
           Summary: [c++-concepts] Bad interaction between deduction guide
                    with decay and constraints
           Product: gcc
           Version: 14.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: daniel.kruegler at googlemail dot com
  Target Milestone: ---

The following simplified code snippet demonstrates a breakage our company code
when updating gcc from C++17 to C++20. I'm starting first with the original
example, because it provides a bit more context information:

------------------------------------
#include <utility>

void value_twice(int& result)
{
  result = 2 * result;
}

auto key_value_gen()
{
  return std::pair("key", value_twice);
}

int main()
{
}
------------------------------------

Using gcc HEAD 14.0.0 20230728 and compiled with the previous settings
-Wall -Wextra -pedantic -std=c++17
the code is accepted, but switching to
-Wall -Wextra -pedantic -std=c++20
it becomes rejected with the following diagnostics:

------------------------------------
In file included from /opt/wandbox/gcc-head/include/c++/14.0.0/utility:69,
                 from prog.cc:1:
/opt/wandbox/gcc-head/include/c++/14.0.0/bits/stl_pair.h: In instantiation of
'struct std::pair<char [4], void(int&)>':
/opt/wandbox/gcc-head/include/c++/14.0.0/bits/stl_pair.h:307:57:   required by
substitution of 'template<class _T1, class _T2> pair(const _T1&, const _T2&)->
std::pair<_T1, _T2> requires (std::pair<_T1, _T2>::_S_constructible<const _T1&,
const _T2&>)() [with _T1 = char [4]; _T2 = void(int&)]'
prog.cc:10:38:   required from here
/opt/wandbox/gcc-head/include/c++/14.0.0/bits/stl_pair.h:194:11: error: data
member 'std::pair<char [4], void(int&)>::second' invalidly declared function
type
  194 |       _T2 second;                ///< The second member
      |           ^~~~~~
------------------------------------
Note that std::pair has a "decaying" deduction guide

template<class T1, class T2>
pair(T1, T2) -> pair<T1, T2>;

but the error message reveals that attempts the produce a std::pair of the
undecayed types.

Additional information:
a) Current MSVC accepts the code but clang also rejects it but for different
reasons than gcc (see below).
b) I'm aware that a simple workaround exists by returning std::pair("key",
&value_twice) instead, and this is what we did to fix this. Nonetheless I think
that not everyone is able to fix such a problem in similar code when it was
provided by thirdparty libraries.

Basically the same error occurs when we use std::tuple(value_twice) instead.

The C++20 std::pair implementation uses noexcept, conditional explicit, and
trailing requires-clause based on static member functions as predicates, but
for gcc the problem can be reduced to the trailing requires-clause alone:

--------------------------------------
#define WITH_FUNC 1

template<class T>
constexpr bool is_copy_constructible_v = true;

template<class T1>
struct p
{
  T1 first;

  static constexpr bool do_is_copy_constructible()
  {
    return true;
  }

  p(const T1& t1) 
     requires (
#if WITH_FUNC
      do_is_copy_constructible()  // Line 19
#else
      is_copy_constructible_v<T1>
#endif
     )
      : first(t1) 
    {}
};

template<class T1>
p(T1) -> p<T1>;

void value_twice(int& result)
{
  result = 2 * result;
}

auto value_gen()
{
  return p(value_twice); // line 38
}

int main() {}
--------------------------------------

If we define WITH_FUNC to 0, the code is accepted, otherwise (as shown above),
the code is rejected with:

--------------------------------------
prog.cc: In instantiation of 'struct p<void(int&)>':
prog.cc:19:31:   required by substitution of 'template<class T1> p(const T1&)->
p<T1> requires (p<T1>::do_is_copy_constructible)() [with T1 = void(int&)]'
prog.cc:38:23:   required from here
prog.cc:9:6: error: data member 'p<void(int&)>::first' invalidly declared
function type
    9 |   T1 first;
      |      ^~~~~
--------------------------------------

Note that clang does accept the reduced case, even though it rejects the
original example as well due to slightly different reasons, which I will report
separately to them.

The reduced case uses the same implementation strategy as libstdc++ by means of
a static member function. What's special here is that the body of such a
function is a complete-class context of p, which I guess causes the error here
because the trailing requires-clause is not a complete-class context of p, so
one could say that this is actually a libstdc++ defect to use this
implementation strategy, it seems odd to me that the compiler attempts to
instantiate p with the undecayed function here and would like to open this
initially as compiler defect since the corresponding function does not actually
depend on p being complete. Feel free to correct me, but in case of a
correction of my understanding I would like to change this to a libstdc++ issue
instead of closing it because that would mean that libstdc++ cannot use there
static member function predicate approach (A free function template could be
used instead of a static member function, I tested that).

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

* [Bug libstdc++/110853] [c++-concepts] Bad interaction between deduction guide with decay and constraints
  2023-07-30 14:05 [Bug c++/110853] New: [c++-concepts] Bad interaction between deduction guide with decay and constraints daniel.kruegler at googlemail dot com
@ 2023-08-07 14:08 ` ppalka at gcc dot gnu.org
  0 siblings, 0 replies; 2+ messages in thread
From: ppalka at gcc dot gnu.org @ 2023-08-07 14:08 UTC (permalink / raw)
  To: gcc-bugs

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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |ppalka at gcc dot gnu.org

--- Comment #1 from Patrick Palka <ppalka at gcc dot gnu.org> ---
Since as you mention a member function body is a complete-class context,
libstdc++'s std::pair implementation strategy does seem non-conforming in this
case.

Clang seems to not propagate constructor constraints to the implicit deduction
guide, according to the following example, and is probably the reason why it
accepts your reduced example.

template<class T>
struct A {
  A(T) requires false; // #1
  A(...); // #2
};

auto a = A(0); // GCC rejects, Clang incorrectly(?) selects #2 with T=int.

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

end of thread, other threads:[~2023-08-07 14:08 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-30 14:05 [Bug c++/110853] New: [c++-concepts] Bad interaction between deduction guide with decay and constraints daniel.kruegler at googlemail dot com
2023-08-07 14:08 ` [Bug libstdc++/110853] " ppalka at gcc dot gnu.org

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).