Commit c3d4dbc6 by Jason Merrill

c++: Refinements to "more constrained".

P2113 from the last C++ meeting clarified that we only compare constraints
on functions or function templates that have equivalent template parameters
and function parameters.

I'm not currently implementing the complicated handling of reversed
comparison operators here; thinking about it now, it seems like a lot of
complexity to support a very weird usage.  If I write two similar comparison
operators to be distinguished by their constraints, why would I write one
reversed?  If they're two unrelated operators, they're very unlikely to be
similar enough for the complexity to help.  I've started a discussion on the
committee reflector about changing these rules.

This change breaks some greedy_ops tests in libstdc++ that were relying on
comparing constraints on unrelated templates, which seems pretty clearly
wrong, so I'm removing those tests for now.

gcc/cp/ChangeLog:

	* call.c (joust): Only compare constraints for non-template
	candidates with matching parameters.
	* pt.c (tsubst_pack_expansion): Fix getting a type parameter
	pack.
	(more_specialized_fn): Only compare constraints for candidates with
	matching parameters.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/concepts-return-req1.C: Expect error.
	* g++.dg/cpp2a/concepts-p2113a.C: New test.
	* g++.dg/cpp2a/concepts-p2113b.C: New test.

libstdc++-v3/ChangeLog:

	* testsuite/24_iterators/move_iterator/rel_ops_c++20.cc:
	Remove greedy_ops tests.
	* testsuite/24_iterators/reverse_iterator/rel_ops_c++20.cc:
	Remove greedy_ops tests.
parent 1271bdf0
...@@ -11440,12 +11440,13 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, ...@@ -11440,12 +11440,13 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
return winner; 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 if (flag_concepts && DECL_P (cand1->fn) && DECL_P (cand2->fn)
be computed a separate time. This needs to be validated, and if && !cand1->template_decl && !cand2->template_decl
so, the redundant check removed. */ && cand_parms_match (cand1, cand2))
if (flag_concepts && DECL_P (cand1->fn) && DECL_P (cand2->fn))
{ {
winner = more_constrained (cand1->fn, cand2->fn); winner = more_constrained (cand1->fn, cand2->fn);
if (winner) if (winner)
......
...@@ -12871,6 +12871,10 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, ...@@ -12871,6 +12871,10 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
template_parm_level_and_index (parm_pack, &level, &idx); template_parm_level_and_index (parm_pack, &level, &idx);
if (level <= levels) if (level <= levels)
arg_pack = TMPL_ARG (args, level, idx); 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; orig_arg = arg_pack;
...@@ -24145,7 +24149,15 @@ more_specialized_fn (tree pat1, tree pat2, int len) ...@@ -24145,7 +24149,15 @@ more_specialized_fn (tree pat1, tree pat2, int len)
/* If both deductions succeed, the partial ordering selects the more /* If both deductions succeed, the partial ordering selects the more
constrained template. */ 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); int winner = more_constrained (decl1, decl2);
if (winner > 0) if (winner > 0)
......
// 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" }
// 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
}
...@@ -15,5 +15,5 @@ int f(...); ...@@ -15,5 +15,5 @@ int f(...);
int main() int main()
{ {
f<int>(); f<int>(); // { dg-error "ambiguous" }
} }
...@@ -142,22 +142,3 @@ static_assert( cend > beg ); ...@@ -142,22 +142,3 @@ static_assert( cend > beg );
static_assert( beg <= cend ); static_assert( beg <= cend );
static_assert( cend >= beg ); static_assert( cend >= beg );
static_assert( std::is_lt(beg <=> cend) ); 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;
}
...@@ -169,25 +169,3 @@ static_assert( crend > rbeg ); ...@@ -169,25 +169,3 @@ static_assert( crend > rbeg );
static_assert( rbeg <= crend ); static_assert( rbeg <= crend );
static_assert( crend >= rbeg ); static_assert( crend >= rbeg );
static_assert( std::is_lt(rbeg <=> crend) ); 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment