]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Refinements to "more constrained".
authorJason Merrill <jason@redhat.com>
Fri, 12 Jun 2020 03:58:54 +0000 (23:58 -0400)
committerJason Merrill <jason@redhat.com>
Mon, 22 Jun 2020 19:33:35 +0000 (15:33 -0400)
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.

gcc/cp/call.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp2a/concepts-p2113a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/concepts-p2113b.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/concepts-return-req1.C
libstdc++-v3/testsuite/24_iterators/move_iterator/rel_ops_c++20.cc
libstdc++-v3/testsuite/24_iterators/reverse_iterator/rel_ops_c++20.cc

index 07d1215c560fb7a752a42e20e7416af2f29d3172..a226a5c4d3e6a7c2e47facf503318d48946358c9 100644 (file)
@@ -11440,12 +11440,13 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
        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)
index 5505a85dcc77bfaaec4b9fb28fbaa33d14a19418..f0aa626ab723ad542c4416f429ead7ca9b570718 100644 (file)
@@ -12871,6 +12871,10 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
           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;
@@ -24145,7 +24149,15 @@ more_specialized_fn (tree pat1, tree pat2, int len)
 
   /* 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)
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-p2113a.C b/gcc/testsuite/g++.dg/cpp2a/concepts-p2113a.C
new file mode 100644 (file)
index 0000000..e2652dd
--- /dev/null
@@ -0,0 +1,12 @@
+// 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" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-p2113b.C b/gcc/testsuite/g++.dg/cpp2a/concepts-p2113b.C
new file mode 100644 (file)
index 0000000..18c4098
--- /dev/null
@@ -0,0 +1,25 @@
+// 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
+}
index 1d005f059d0dd8478d330c39a450781d03dda4ce..8eebba6fdccfbaef7732cc9942841cab714a7e62 100644 (file)
@@ -15,5 +15,5 @@ int f(...);
 
 int main()
 {
-  f<int>();
+  f<int>();                    // { dg-error "ambiguous" }
 }
index a530923f8ad3a40cbf845488853846337ebb1bca..b298a312aae7cba6bb0cce2addbee72c961b3486 100644 (file)
@@ -142,22 +142,3 @@ static_assert( cend > beg );
 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;
-}
index a382ae524832decebf3aecfbd5235fa997120bc1..e513efba57f8bc128e051d819ed11f59221356ef 100644 (file)
@@ -169,25 +169,3 @@ static_assert( crend > rbeg );
 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;
-}