return winner;
}
- /* Concepts: ... or, if not that, F1 is more constrained than F2.
+ /* Concepts: F1 and F2 are non-template functions with the same
+ parameter-type-lists, and F1 is more constrained than F2 according to the
+ partial ordering of constraints described in 13.5.4. */
- FIXME: For function templates with no winner, this subsumption may
- be computed a separate time. This needs to be validated, and if
- so, the redundant check removed. */
- if (flag_concepts && DECL_P (cand1->fn) && DECL_P (cand2->fn))
+ if (flag_concepts && DECL_P (cand1->fn) && DECL_P (cand2->fn)
+ && !cand1->template_decl && !cand2->template_decl
+ && cand_parms_match (cand1, cand2))
{
winner = more_constrained (cand1->fn, cand2->fn);
if (winner)
template_parm_level_and_index (parm_pack, &level, &idx);
if (level <= levels)
arg_pack = TMPL_ARG (args, level, idx);
+
+ if (arg_pack && TREE_CODE (arg_pack) == TEMPLATE_TYPE_PARM
+ && TEMPLATE_TYPE_PARAMETER_PACK (arg_pack))
+ arg_pack = NULL_TREE;
}
orig_arg = arg_pack;
/* If both deductions succeed, the partial ordering selects the more
constrained template. */
- if (!lose1 && !lose2)
+ /* P2113: If the corresponding template-parameters of the
+ template-parameter-lists are not equivalent ([temp.over.link]) or if
+ the function parameters that positionally correspond between the two
+ templates are not of the same type, neither template is more
+ specialized than the other. */
+ if (!lose1 && !lose2
+ && comp_template_parms (DECL_TEMPLATE_PARMS (pat1),
+ DECL_TEMPLATE_PARMS (pat2))
+ && compparms (origs1, origs2))
{
int winner = more_constrained (decl1, decl2);
if (winner > 0)
--- /dev/null
+// Test that the second foo is not considered more specialized because we don't
+// compare constraints unless the template parameters and function parameters
+// are equivalent (P2113)
+
+// { dg-do compile { target c++20 } }
+
+template <typename T> concept P = true;
+
+template <typename T> void foo(int, T);
+template <P U> void foo(U, int);
+
+void bar() { foo(1,2); } // { dg-error "ambiguous" }
--- /dev/null
+// testcase from P2113
+// { dg-do compile { target c++20 } }
+
+template <typename> constexpr bool True = true;
+template <typename T> concept C = True<T>;
+
+void f(C auto &, auto &) = delete;
+template <C Q> void f(Q &, C auto &);
+
+void g(struct A *ap, struct B *bp) {
+ f(*ap, *bp); // OK: Can use different methods to produce template parameters
+}
+
+template <typename T, typename U> struct X {};
+
+template <typename T1, C U1, typename V1>
+bool operator==(X<T1, U1>, V1) = delete;
+
+// In P2113 this candidate is reversed.
+template <C T2, C U2, C V2>
+bool operator==(X<T2, U2>, V2);
+
+void h() {
+ X<void *, int>{} == 0; // OK
+}
int main()
{
- f<int>();
+ f<int>(); // { dg-error "ambiguous" }
}
static_assert( beg <= cend );
static_assert( cend >= beg );
static_assert( std::is_lt(beg <=> cend) );
-
-#include <testsuite_greedy_ops.h>
-
-void test01()
-{
- typedef std::move_iterator<greedy_ops::X*> iterator_type;
-
- iterator_type it(nullptr);
-
- it == it;
- it != it;
- it < it;
- it <= it;
- it > it;
- it >= it;
- // it - it; // See PR libstdc++/71771
- 1 + it;
- it + 1;
-}
static_assert( rbeg <= crend );
static_assert( crend >= rbeg );
static_assert( std::is_lt(rbeg <=> crend) );
-
-#include <testsuite_greedy_ops.h>
-
-// copied from 24_iterators/reverse_iterator/greedy_ops.cc
-void test01()
-{
- typedef std::reverse_iterator<greedy_ops::X*> iterator_type;
-
- iterator_type it;
-
- it == it;
- it != it;
- it < it;
- it <= it;
- it > it;
- it >= it;
-#if __cplusplus < 201103L
- it - it; // See PR libstdc++/71771
-#endif
- 1 + it;
- it + 1;
-}