[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