[Bug c++/93152] New: Order of template args in decl makes std::invocable fail

db0451 at gmail dot com gcc-bugzilla@gcc.gnu.org
Sat Jan 4 17:16:00 GMT 2020


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

            Bug ID: 93152
           Summary: Order of template args in decl makes std::invocable
                    fail
           Product: gcc
           Version: 10.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: db0451 at gmail dot com
  Target Milestone: ---

This is as far as I've yet reduced this from my own project, compiling with
`g++-10 (Debian 10-20191217-1) 10.0.0 20191217 (experimental) [trunk revision
279456]`

From the comments below:

// Putting Result as 1st template argument makes derived_from<WeirdBase> fail,
// but putting derived_from<WeirdBase> 1st lets it compile without problem!
// If you [constrain via static_assert] instead, both template arg orders
work!!

The failure occurs like so; it seems that somehow g++ concludes the wrong base
for derived_from, and as mentioned that seems to be caused by template arg
order

>>>
test3.cpp: In function ‘int main()’:
test3.cpp:48:33: error: no match for call to ‘(const
make_lambda(MemFun<WeirdSub1, Result, Args ...>) [with Result = void; WeirdSub1
= WeirdSub; Args = {}; MemFun<WeirdSub1, Result, Args ...> = void
(WeirdSub::*)()]::<lambda(auto:1&&, auto:2&&)>) (WeirdSub, OtherSub)’
   48 |  lambda( WeirdSub{}, OtherSub{} );
      |                                 ^
test3.cpp:28:9: note: candidate: ‘make_lambda(MemFun<WeirdSub1, Result, Args
...>) [with Result = void; WeirdSub1 = WeirdSub; Args = {}; MemFun<WeirdSub1,
Result, Args ...> = void (WeirdSub::*)()]::<lambda(auto:1&&, auto:2&&)> [with
auto:1 = WeirdSub; auto:2 = OtherSub]’
   28 |  return []
      |         ^
test3.cpp:28:9: note: constraints not satisfied
In file included from test3.cpp:1:
/usr/include/c++/10/concepts: In instantiation of
‘make_lambda(MemFun<WeirdSub1, Result, Args ...>) [with Result = void;
WeirdSub1 = WeirdSub; Args = {}; MemFun<WeirdSub1, Result, Args ...> = void
(WeirdSub::*)()]::<lambda(auto:1&&, auto:2&&)> [with auto:1 = WeirdSub; auto:2
= OtherSub]’:
test3.cpp:48:33:   required from here
/usr/include/c++/10/concepts:67:13:   required for the satisfaction of
‘derived_from<auto:1, OtherSub>’
/usr/include/c++/10/concepts:67:28: note:   ‘OtherSub’ is not a base of
‘WeirdSub’
   67 |     concept derived_from = __is_base_of(_Base, _Derived)

>>>

Additionally, if you make the lambda instead take only derived_from<WeirdSub1>,
and dutifully pass only that... then an ICE occurs instead. I'll probably file
a 2nd, simpler MCVE for that - unless it turns out to have the same root cause.

>>>
test3.cpp: In function ‘int main()’:
test3.cpp:48:21: internal compiler error: Segmentation fault
   48 |  lambda( WeirdSub{} );//, OtherSub{} );
      |                     ^
0xbecf3f crash_signal
        ../../src/gcc/toplev.c:328
0x7fb9a36f30ff ???
       
/build/glibc-dEjGnz/glibc-2.29/signal/../sysdeps/unix/sysv/linux/x86_64/sigaction.c:0
0x703e96 tsubst(tree_node*, tree_node*, int, tree_node*)
        ../../src/gcc/cp/pt.c:15083
0x707ac6 tsubst_template_args(tree_node*, tree_node*, int, tree_node*)
        ../../src/gcc/cp/pt.c:13099
0x625fa5 normalize_concept_check
        ../../src/gcc/cp/constraint.cc:685
0x625fa5 normalize_atom
        ../../src/gcc/cp/constraint.cc:719
0x625fa5 normalize_expression
        ../../src/gcc/cp/constraint.cc:748
0x6263da get_normalized_constraints
        ../../src/gcc/cp/constraint.cc:760
0x6263da get_normalized_constraints_from_info
        ../../src/gcc/cp/constraint.cc:778
0x629dfd get_normalized_constraints_from_decl
        ../../src/gcc/cp/constraint.cc:841
0x62a23a satisfy_declaration_constraints
        ../../src/gcc/cp/constraint.cc:880
0x62a578 constraint_satisfaction_value
        ../../src/gcc/cp/constraint.cc:2709
0x62a578 constraints_satisfied_p(tree_node*)
        ../../src/gcc/cp/constraint.cc:2730
0x5f7f11 add_function_candidate
        ../../src/gcc/cp/call.c:2280
0x5fa28d add_template_candidate_real
        ../../src/gcc/cp/call.c:3438
0x5fa7c4 add_template_candidate
        ../../src/gcc/cp/call.c:3479
0x5fa7c4 add_candidates
        ../../src/gcc/cp/call.c:5805
0x5ff654 add_candidates
        ../../src/gcc/cp/call.c:5720
0x5ff654 build_op_call_1
        ../../src/gcc/cp/call.c:4768
0x5ff654 build_op_call(tree_node*, vec<tree_node*, va_gc, vl_embed>**, int)
        ../../src/gcc/cp/call.c:4864
>>>

***

```
#include <concepts>
#include <type_traits>

struct WeirdBase {};

struct WeirdSub: WeirdBase {
        void mem_fun() {}
};

struct OtherBase {};
struct OtherSub: OtherBase {};

template <typename Object, typename Result, typename... Args>
using MemFun = Result (Object::*)(Args...);

// Putting Result as 1st template argument makes derived_from<WeirdBase> fail,
#if 1
template <typename Result, std::derived_from<WeirdBase> WeirdSub1,
          typename... Args>
// but putting derived_from<WeirdBase> 1st lets it compile without problem!
#else
template <std::derived_from<WeirdBase> WeirdSub1,
          typename Result, typename... Args>
#endif
auto
make_lambda( MemFun<WeirdSub1, Result, Args...> )
{
        return []
#if 1
               (std::derived_from<WeirdSub1> auto&&,
                std::derived_from<OtherBase> auto&&)
        {
// If you do the following instead, both template arg orders work!!
#else
               (std::derived_from<WeirdBase> auto&& weird,
                std::derived_from<OtherBase> auto&&)
        {
                using WeirdSub2 = std::remove_reference_t< decltype(weird) >;
                static_assert( std::derived_from<WeirdSub2, WeirdSub1> );
#endif
        };
}

auto
main() -> int
{
        auto const lambda = make_lambda(&WeirdSub::mem_fun);
        lambda( WeirdSub{}, OtherSub{} );

        return 0;
}
```


More information about the Gcc-bugs mailing list