public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: CTAD and deduction guide selection [PR86439]
@ 2021-06-22 18:45 Patrick Palka
  2021-06-22 19:56 ` Jason Merrill
  2021-06-22 20:05 ` Jonathan Wakely
  0 siblings, 2 replies; 5+ messages in thread
From: Patrick Palka @ 2021-06-22 18:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, jason, Patrick Palka

During CTAD, we select the best viable deduction guide via
build_new_function_call, which performs overload resolution on the set
of candidate guides and then forms a call to the guide.  As the PR
points out, this latter step is unnecessary and occasionally gives us
the wrong answer since a call to the selected guide may be ill-formed,
or forming the call may have side effects such as prematurely deducing
the type of a {}.

This patch introduces a specialized subroutine modeled off of
build_new_function_call that stops short of building a call to the
selected function, and makes do_class_deduction use this subroutine
instead.  And since we no longer build a call, do_class_deduction
doesn't need to set tf_decltype or cp_unevaluated_operand.

This change causes us to reject some container CTAD examples in the
libstdc++ testsuite due to deduction failure for {}, which AFAICT is the
correct behavior.  Previously, in the case of e.g. the first removed
example for std::map, the type of {} would be deduced to less<int> as a
side effect of forming the call to the selected guide

  template<typename _Key, typename _Tp, typename _Compare = less<_Key>,
             typename _Allocator = allocator<pair<const _Key, _Tp>>,
             typename = _RequireNotAllocator<_Compare>,
             typename = _RequireAllocator<_Allocator>>
      map(initializer_list<pair<_Key, _Tp>>,
          _Compare = _Compare(), _Allocator = _Allocator())
      -> map<_Key, _Tp, _Compare, _Allocator>;

which made later overload resolution for the constructor call
unambiguous.  Now, the type of {} remains undeduced until constructor
overload resolution, and we complain about ambiguity with the two
constructors

  map(initializer_list<value_type> __l,
      const _Compare& __comp = _Compare(),
      const allocator_type& __a = allocator_type())

  map(initializer_list<value_type> __l, const allocator_type& __a)

This patch just removes these problematic container CTAD examples.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

	PR c++/86439

gcc/cp/ChangeLog:

	* call.c (print_error_for_call_failure): Constify 'args'
	parameter.
	(perform_dguide_overload_resolution): Define.
	* cp-tree.h: (perform_dguide_overload_resolution): Declare.
	* pt.c (do_class_deduction): Use perform_dguide_overload_resolution
	instead of build_new_function_call.  Don't use tf_decltype or
	set cp_unevaluated_operand.  Remove unnecessary NULL_TREE tests.

libstdc++-v3/ChangeLog:

	* testsuite/23_containers/map/cons/deduction.cc: Remove
	ambiguous CTAD constructs.
	* testsuite/23_containers/multimap/cons/deduction.cc: Likewise.
	* testsuite/23_containers/multiset/cons/deduction.cc: Likewise.
	* testsuite/23_containers/set/cons/deduction.cc: Likewise.
	* testsuite/23_containers/unordered_map/cons/deduction.cc: Likewise.
	* testsuite/23_containers/unordered_multimap/cons/deduction.cc:
	Likewise.
	* testsuite/23_containers/unordered_multiset/cons/deduction.cc:
	Likewise.
	* testsuite/23_containers/unordered_set/cons/deduction.cc: Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp1z/class-deduction88.C: New test.
	* g++.dg/cpp1z/class-deduction89.C: New test.
	* g++.dg/cpp1z/class-deduction90.C: New test.
---
 gcc/cp/call.c                                 | 36 +++++++++++++++-
 gcc/cp/cp-tree.h                              |  2 +
 gcc/cp/pt.c                                   | 41 +++++++------------
 .../g++.dg/cpp1z/class-deduction88.C          | 20 +++++++++
 .../g++.dg/cpp1z/class-deduction89.C          | 15 +++++++
 .../g++.dg/cpp1z/class-deduction90.C          | 16 ++++++++
 .../23_containers/map/cons/deduction.cc       | 19 ---------
 .../23_containers/multimap/cons/deduction.cc  | 20 ---------
 .../23_containers/multiset/cons/deduction.cc  | 14 -------
 .../23_containers/set/cons/deduction.cc       | 15 -------
 .../unordered_map/cons/deduction.cc           | 16 --------
 .../unordered_multimap/cons/deduction.cc      | 16 --------
 .../unordered_multiset/cons/deduction.cc      | 10 -----
 .../unordered_set/cons/deduction.cc           | 10 -----
 14 files changed, 102 insertions(+), 148 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction88.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction89.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction90.C

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 9f03534c20c..aafc7acca24 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4629,7 +4629,7 @@ perform_overload_resolution (tree fn,
    functions.  */
 
 static void
-print_error_for_call_failure (tree fn, vec<tree, va_gc> *args,
+print_error_for_call_failure (tree fn, const vec<tree, va_gc> *args,
 			      struct z_candidate *candidates)
 {
   tree targs = NULL_TREE;
@@ -4654,6 +4654,40 @@ print_error_for_call_failure (tree fn, vec<tree, va_gc> *args,
     print_z_candidates (loc, candidates);
 }
 
+/* Perform overload resolution on the set of deduction guides DGUIDES
+   using ARGS.  Returns the selected deduction guide, or error_mark_node
+   if overload resolution fails.  */
+
+tree
+perform_dguide_overload_resolution (tree dguides, const vec<tree, va_gc> *args,
+				    tsubst_flags_t complain)
+{
+  z_candidate *candidates;
+  bool any_viable_p;
+  tree result;
+
+  gcc_assert (deduction_guide_p (OVL_FIRST (dguides)));
+
+  /* Get the high-water mark for the CONVERSION_OBSTACK.  */
+  void *p = conversion_obstack_alloc (0);
+
+  z_candidate *cand = perform_overload_resolution (dguides, args, &candidates,
+						   &any_viable_p, complain);
+  if (!cand)
+    {
+      if (complain & tf_error)
+	print_error_for_call_failure (dguides, args, candidates);
+      result = error_mark_node;
+    }
+  else
+    result = cand->fn;
+
+  /* Free all the conversions we allocated.  */
+  obstack_free (&conversion_obstack, p);
+
+  return result;
+}
+
 /* Return an expression for a call to FN (a namespace-scope function,
    or a static member function) with the ARGS.  This may change
    ARGS.  */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 36f99ccf189..6f713719589 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6437,6 +6437,8 @@ extern void complain_about_bad_argument	(location_t arg_loc,
 						 tree from_type, tree to_type,
 						 tree fndecl, int parmnum);
 extern void maybe_inform_about_fndecl_for_bogus_argument_init (tree, int);
+extern tree perform_dguide_overload_resolution	(tree, const vec<tree, va_gc> *,
+						 tsubst_flags_t);
 
 
 /* A class for recording information about access failures (e.g. private
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 15947b2c812..732fb405adf 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -29382,7 +29382,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
     if (tree guide = maybe_aggr_guide (tmpl, init, args))
       cands = lookup_add (guide, cands);
 
-  tree call = error_mark_node;
+  tree fndecl = error_mark_node;
 
   /* If this is list-initialization and the class has a list constructor, first
      try deducing from the list as a single argument, as [over.match.list].  */
@@ -29396,11 +29396,9 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
       }
   if (list_cands)
     {
-      ++cp_unevaluated_operand;
-      call = build_new_function_call (list_cands, &args, tf_decltype);
-      --cp_unevaluated_operand;
+      fndecl = perform_dguide_overload_resolution (list_cands, args, tf_none);
 
-      if (call == error_mark_node)
+      if (fndecl == error_mark_node)
 	{
 	  /* That didn't work, now try treating the list as a sequence of
 	     arguments.  */
@@ -29416,31 +29414,22 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
 	     "user-declared constructors", type);
       return error_mark_node;
     }
-  else if (!cands && call == error_mark_node)
+  else if (!cands && fndecl == error_mark_node)
     {
       error ("cannot deduce template arguments of %qT, as it has no viable "
 	     "deduction guides", type);
       return error_mark_node;
     }
 
-  if (call == error_mark_node)
-    {
-      ++cp_unevaluated_operand;
-      call = build_new_function_call (cands, &args, tf_decltype);
-      --cp_unevaluated_operand;
-    }
+  if (fndecl == error_mark_node)
+    fndecl = perform_dguide_overload_resolution (cands, args, tf_none);
 
-  if (call == error_mark_node)
+  if (fndecl == error_mark_node)
     {
       if (complain & tf_warning_or_error)
 	{
 	  error ("class template argument deduction failed:");
-
-	  ++cp_unevaluated_operand;
-	  call = build_new_function_call (cands, &args,
-					  complain | tf_decltype);
-	  --cp_unevaluated_operand;
-
+	  perform_dguide_overload_resolution (cands, args, complain);
 	  if (elided)
 	    inform (input_location, "explicit deduction guides not considered "
 		    "for copy-initialization");
@@ -29451,8 +29440,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
      constructor is chosen, the initialization is ill-formed.  */
   else if (flags & LOOKUP_ONLYCONVERTING)
     {
-      tree fndecl = cp_get_callee_fndecl_nofold (call);
-      if (fndecl && DECL_NONCONVERTING_P (fndecl))
+      if (DECL_NONCONVERTING_P (fndecl))
 	{
 	  if (complain & tf_warning_or_error)
 	    {
@@ -29470,12 +29458,10 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
 
   /* If CTAD succeeded but the type doesn't have any explicit deduction
      guides, this deduction might not be what the user intended.  */
-  if (call != error_mark_node && !any_dguides_p)
+  if (fndecl != error_mark_node && !any_dguides_p)
     {
-      tree fndecl = cp_get_callee_fndecl_nofold (call);
-      if (fndecl != NULL_TREE
-	  && (!DECL_IN_SYSTEM_HEADER (fndecl)
-	      || global_dc->dc_warn_system_headers)
+      if ((!DECL_IN_SYSTEM_HEADER (fndecl)
+	   || global_dc->dc_warn_system_headers)
 	  && warning (OPT_Wctad_maybe_unsupported,
 		      "%qT may not intend to support class template argument "
 		      "deduction", type))
@@ -29483,7 +29469,8 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
 		"warning");
     }
 
-  return cp_build_qualified_type (TREE_TYPE (call), cp_type_quals (ptype));
+  return cp_build_qualified_type (TREE_TYPE (TREE_TYPE (fndecl)),
+				  cp_type_quals (ptype));
 }
 
 /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction88.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction88.C
new file mode 100644
index 00000000000..f8fea966696
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction88.C
@@ -0,0 +1,20 @@
+// PR c++/86439
+// { dg-do compile { target c++17 } }
+
+struct NC {
+  NC() = default;
+  NC(NC const&) = delete;
+  NC& operator=(NC const&) = delete;
+};
+
+template <int>
+struct C {
+  C(NC const&);
+};
+
+C(NC) -> C<0>;
+
+int main() {
+  NC nc;
+  C c(nc);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction89.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction89.C
new file mode 100644
index 00000000000..dd898573022
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction89.C
@@ -0,0 +1,15 @@
+// PR c++/86439
+// { dg-do compile { target c++17 } }
+
+struct B { };
+struct C { };
+
+template<class T>
+struct A {
+  A(T, B);
+};
+
+template<class T>
+A(T, C) -> A<T>;
+
+A a(0, {});
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction90.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction90.C
new file mode 100644
index 00000000000..8b93193c7b0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction90.C
@@ -0,0 +1,16 @@
+// PR c++/86439
+// { dg-do compile { target c++17 } }
+
+struct less { };
+struct allocator { };
+
+template<class T, class U = less, class V = allocator>
+struct A {
+  A(T, U);
+  A(T, V);
+};
+
+template<class T, class U = less>
+A(T, U) -> A<T>;
+
+A a(0, {}); // { dg-error "ambiguous" }
diff --git a/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc
index e9628c4ac32..8def11ed574 100644
--- a/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc
@@ -39,10 +39,6 @@ static_assert(std::is_same_v<
 	      std::map<int, double>>);
 */
 
-static_assert(std::is_same_v<
-	      decltype(std::map{{std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}}, {}}),
-	      std::map<int, double>>);
-
 /* This is not deducible, ambiguous candidates:
  * map(initializer_list<value_type>, const Compare&, const _Allocator& = {})
  * map(initializer_list<value_type>, const _Allocator&)
@@ -90,11 +86,6 @@ void f()
 				  std::less<int>{}, {}}),
 		std::map<int, double>>);
 
-  static_assert(std::is_same_v<
-		decltype(std::map(x.begin(), x.end(),
-				  {})),
-		std::map<int, double>>);
-
   static_assert(std::is_same_v<
 		decltype(std::map{x.begin(), x.end(),
 				  std::allocator<value_type>{}}),
@@ -143,11 +134,6 @@ void g()
 				  std::less<int>{}, {}}),
 		std::map<int, double>>);
 
-  static_assert(std::is_same_v<
-		decltype(std::map(x.begin(), x.end(),
-				  {})),
-		std::map<int, double>>);
-
   static_assert(std::is_same_v<
 		decltype(std::map{x.begin(), x.end(),
 				  std::allocator<value_type>{}}),
@@ -193,11 +179,6 @@ void h()
 				  std::less<int>{}, {}}),
 		std::map<int, double>>);
 
-  static_assert(std::is_same_v<
-		decltype(std::map(x.begin(), x.end(),
-				  {})),
-		std::map<int, double>>);
-
   static_assert(std::is_same_v<
 		decltype(std::map{x.begin(), x.end(),
 				  std::allocator<value_type>{}}),
diff --git a/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc
index 791cc963479..ff855081ab3 100644
--- a/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc
@@ -40,11 +40,6 @@ static_assert(std::is_same_v<
 	      std::multimap<int, double>>);
 */
 
-static_assert(std::is_same_v<
-	      decltype(std::multimap{{std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}},
-		    {}}),
-	      std::multimap<int, double>>);
-
 static_assert(std::is_same_v<
 	      decltype(std::multimap{{value_type{1, 2.0}, {2, 3.0}, {3, 4.0}},
 				     {}, SimpleAllocator<value_type>{}}),
@@ -75,11 +70,6 @@ void f()
 				       std::less<int>{}, {}}),
 		std::multimap<int, double>>);
 
-  static_assert(std::is_same_v<
-		decltype(std::multimap(x.begin(), x.end(),
-				       {})),
-		std::multimap<int, double>>);
-
   static_assert(std::is_same_v<
 		decltype(std::multimap{x.begin(), x.end(),
 		      {},
@@ -117,11 +107,6 @@ void g()
 				       std::less<int>{}, {}}),
 		std::multimap<int, double>>);
 
-  static_assert(std::is_same_v<
-		decltype(std::multimap(x.begin(), x.end(),
-				       {})),
-		std::multimap<int, double>>);
-
   static_assert(std::is_same_v<
 		decltype(std::multimap{x.begin(), x.end(),
 				       {},
@@ -156,11 +141,6 @@ void h()
 				       std::less<int>{}, {}}),
 		std::multimap<int, double>>);
 
-  static_assert(std::is_same_v<
-		decltype(std::multimap(x.begin(), x.end(),
-				       {})),
-		std::multimap<int, double>>);
-
   static_assert(std::is_same_v<
 		decltype(std::multimap{x.begin(), x.end(),
 				       {},
diff --git a/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc
index ad12755ccc6..be7ca237e78 100644
--- a/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc
@@ -19,10 +19,6 @@ static_assert(std::is_same_v<
 	      decltype(std::multiset{{1, 2, 3}, std::less<int>{}, {}}),
 	      std::multiset<int>>);
 
-static_assert(std::is_same_v<
-	      decltype(std::multiset{{1, 2, 3}, {}}),
-	      std::multiset<int>>);
-
 static_assert(std::is_same_v<
 	      decltype(std::multiset{{1, 2, 3}, SimpleAllocator<int>{}}),
 	      std::multiset<int, std::less<int>, SimpleAllocator<int>>>);
@@ -50,11 +46,6 @@ void f()
 		      std::less<int>{}, {}}),
 		std::multiset<int>>);
 
-  static_assert(std::is_same_v<
-		decltype(std::multiset(x.begin(), x.end(),
-				  {})),
-		std::multiset<int>>);
-
   static_assert(std::is_same_v<
 		decltype(std::multiset{x.begin(), x.end(),
 				       std::allocator<int>{}}),
@@ -101,11 +92,6 @@ void g()
 				  std::less<int>{}, {}}),
 		std::multiset<int>>);
 
-  static_assert(std::is_same_v<
-		decltype(std::multiset(x.begin(), x.end(),
-				  {})),
-		std::multiset<int>>);
-
   static_assert(std::is_same_v<
 		decltype(std::multiset{x.begin(), x.end(),
 				  std::allocator<value_type>{}}),
diff --git a/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc
index 89a2c43b937..48d1a3ebbe2 100644
--- a/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc
@@ -20,11 +20,6 @@ static_assert(std::is_same_v<
 		    std::less<int>{}, {}}),
 	      std::set<int>>);
 
-static_assert(std::is_same_v<
-	      decltype(std::set{{1, 2, 3},
-		    {}}),
-	      std::set<int>>);
-
 static_assert(std::is_same_v<
 	      decltype(std::set{{1, 2, 3},
 		    SimpleAllocator<int>{}}),
@@ -56,11 +51,6 @@ void f()
 		      std::less<int>{}, {}}),
 		std::set<int>>);
 
-  static_assert(std::is_same_v<
-		decltype(std::set(x.begin(), x.end(),
-				  {})),
-		std::set<int>>);
-
   static_assert(std::is_same_v<
 		decltype(std::set{x.begin(), x.end(),
 		      {},
@@ -102,11 +92,6 @@ void g()
 				  std::less<int>{}, {}}),
 		std::set<int>>);
 
-  static_assert(std::is_same_v<
-		decltype(std::set(x.begin(), x.end(),
-				  {})),
-		std::set<int>>);
-
   static_assert(std::is_same_v<
 		decltype(std::set{x.begin(), x.end(),
 				  std::allocator<value_type>{}}),
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc
index d8489b23f8a..bd266492b2a 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc
@@ -21,12 +21,6 @@ static_assert(std::is_same_v<
 		1}),
 	      std::unordered_map<int, double>>);
 
-static_assert(std::is_same_v<
-	      decltype(std::unordered_map{{std::pair{1, 2.0},
-		      {2, 3.0}, {3, 4.0}},
-		    {}, std::hash<int>{}, {}}),
-	      std::unordered_map<int, double>>);
-
 static_assert(std::is_same_v<
 	      decltype(std::unordered_map{{std::pair{1, 2.0},
 		      {2, 3.0}, {3, 4.0}},
@@ -57,16 +51,6 @@ void f()
 		      std::allocator<std::pair<const int, double>>{}}),
 		std::unordered_map<int, double>>);
 
-  static_assert(std::is_same_v<
-		decltype(std::unordered_map{x.begin(), x.end(),
-		      {}, std::hash<int>{}, {}}),
-		std::unordered_map<int, double>>);
-  
-  static_assert(std::is_same_v<
-		decltype(std::unordered_map(x.begin(), x.end(),
-		      {})),
-		std::unordered_map<int, double>>);
-
   static_assert(std::is_same_v<
 		decltype(std::unordered_map{x.begin(), x.end(), 1}),
 		std::unordered_map<int, double>>);
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc
index 13f54d43451..74a0165574d 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc
@@ -15,12 +15,6 @@ static_assert(std::is_same_v<
 		      {2, 3.0}, {3, 4.0}}}),
 	      std::unordered_multimap<int, double>>);
 
-static_assert(std::is_same_v<
-	      decltype(std::unordered_multimap{{std::pair{1, 2.0},
-		      {2, 3.0}, {3, 4.0}},
-		    {}, std::hash<int>{}, {}}),
-	      std::unordered_multimap<int, double>>);
-
 static_assert(std::is_same_v<
 	      decltype(std::unordered_multimap{{std::pair{1, 2.0},
 		      {2, 3.0}, {3, 4.0}},
@@ -66,16 +60,6 @@ void f()
 		      std::allocator<std::pair<const int, double>>{}}),
 		std::unordered_multimap<int, double>>);
 
-  static_assert(std::is_same_v<
-		decltype(std::unordered_multimap{x.begin(), x.end(),
-		      {}, std::hash<int>{}, {}}),
-		std::unordered_multimap<int, double>>);
-  
-  static_assert(std::is_same_v<
-		decltype(std::unordered_multimap(x.begin(), x.end(),
-				  {})),
-		std::unordered_multimap<int, double>>);
-
   static_assert(std::is_same_v<
 		decltype(std::unordered_multimap(x.begin(), x.end(), 1)),
 		std::unordered_multimap<int, double>>);
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc
index 1850237e44c..e3006fdbfe3 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc
@@ -9,11 +9,6 @@ static_assert(std::is_same_v<
 	      decltype(std::unordered_multiset{1, 2, 3}),
 	      std::unordered_multiset<int>>);
 
-static_assert(std::is_same_v<
-	      decltype(std::unordered_multiset{{1, 2, 3},
-		    0, std::hash<int>{}, {}}),
-	      std::unordered_multiset<int>>);
-
 static_assert(std::is_same_v<
 	      decltype(std::unordered_multiset{{1, 2, 3},
 		    {}}),
@@ -76,11 +71,6 @@ void f()
 		      std::allocator<int>{}}),
 		std::unordered_multiset<int>>);
 
-  static_assert(std::is_same_v<
-		decltype(std::unordered_multiset{x.begin(), x.end(),
-		      {}, std::hash<int>{}, {}}),
-		std::unordered_multiset<int>>);
-
   static_assert(std::is_same_v<
 		decltype(std::unordered_multiset(x.begin(), x.end(),
 		      {})),
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc
index a745dce0fba..69922cd92e7 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc
@@ -9,11 +9,6 @@ static_assert(std::is_same_v<
 	      decltype(std::unordered_set{1, 2, 3}),
 	      std::unordered_set<int>>);
 
-static_assert(std::is_same_v<
-	      decltype(std::unordered_set{{1, 2, 3},
-		    0, std::hash<int>{}, {}}),
-	      std::unordered_set<int>>);
-
 static_assert(std::is_same_v<
 	      decltype(std::unordered_set{{1, 2, 3},
 		    {}}),
@@ -71,11 +66,6 @@ void f()
 		      std::allocator<int>{}}),
 		std::unordered_set<int>>);
 
-  static_assert(std::is_same_v<
-		decltype(std::unordered_set{x.begin(), x.end(),
-		      {}, std::hash<int>{}, {}}),
-		std::unordered_set<int>>);
-
   static_assert(std::is_same_v<
 		decltype(std::unordered_set(x.begin(), x.end(),
 		      {})),
-- 
2.32.0.93.g670b81a890


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] c++: CTAD and deduction guide selection [PR86439]
  2021-06-22 18:45 [PATCH] c++: CTAD and deduction guide selection [PR86439] Patrick Palka
@ 2021-06-22 19:56 ` Jason Merrill
  2021-06-22 20:05 ` Jonathan Wakely
  1 sibling, 0 replies; 5+ messages in thread
From: Jason Merrill @ 2021-06-22 19:56 UTC (permalink / raw)
  To: Patrick Palka, gcc-patches; +Cc: libstdc++, jason

On 6/22/21 2:45 PM, Patrick Palka wrote:
> During CTAD, we select the best viable deduction guide via
> build_new_function_call, which performs overload resolution on the set
> of candidate guides and then forms a call to the guide.  As the PR
> points out, this latter step is unnecessary and occasionally gives us
> the wrong answer since a call to the selected guide may be ill-formed,
> or forming the call may have side effects such as prematurely deducing
> the type of a {}.
> 
> This patch introduces a specialized subroutine modeled off of
> build_new_function_call that stops short of building a call to the
> selected function, and makes do_class_deduction use this subroutine
> instead.  And since we no longer build a call, do_class_deduction
> doesn't need to set tf_decltype or cp_unevaluated_operand.
> 
> This change causes us to reject some container CTAD examples in the
> libstdc++ testsuite due to deduction failure for {}, which AFAICT is the
> correct behavior.  Previously, in the case of e.g. the first removed
> example for std::map, the type of {} would be deduced to less<int> as a
> side effect of forming the call to the selected guide
> 
>    template<typename _Key, typename _Tp, typename _Compare = less<_Key>,
>               typename _Allocator = allocator<pair<const _Key, _Tp>>,
>               typename = _RequireNotAllocator<_Compare>,
>               typename = _RequireAllocator<_Allocator>>
>        map(initializer_list<pair<_Key, _Tp>>,
>            _Compare = _Compare(), _Allocator = _Allocator())
>        -> map<_Key, _Tp, _Compare, _Allocator>;
> 
> which made later overload resolution for the constructor call
> unambiguous.  Now, the type of {} remains undeduced until constructor
> overload resolution, and we complain about ambiguity with the two
> constructors
> 
>    map(initializer_list<value_type> __l,
>        const _Compare& __comp = _Compare(),
>        const allocator_type& __a = allocator_type())
> 
>    map(initializer_list<value_type> __l, const allocator_type& __a)
> 
> This patch just removes these problematic container CTAD examples.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?

OK.

> 	PR c++/86439
> 
> gcc/cp/ChangeLog:
> 
> 	* call.c (print_error_for_call_failure): Constify 'args'
> 	parameter.
> 	(perform_dguide_overload_resolution): Define.
> 	* cp-tree.h: (perform_dguide_overload_resolution): Declare.
> 	* pt.c (do_class_deduction): Use perform_dguide_overload_resolution
> 	instead of build_new_function_call.  Don't use tf_decltype or
> 	set cp_unevaluated_operand.  Remove unnecessary NULL_TREE tests.
> 
> libstdc++-v3/ChangeLog:
> 
> 	* testsuite/23_containers/map/cons/deduction.cc: Remove
> 	ambiguous CTAD constructs.
> 	* testsuite/23_containers/multimap/cons/deduction.cc: Likewise.
> 	* testsuite/23_containers/multiset/cons/deduction.cc: Likewise.
> 	* testsuite/23_containers/set/cons/deduction.cc: Likewise.
> 	* testsuite/23_containers/unordered_map/cons/deduction.cc: Likewise.
> 	* testsuite/23_containers/unordered_multimap/cons/deduction.cc:
> 	Likewise.
> 	* testsuite/23_containers/unordered_multiset/cons/deduction.cc:
> 	Likewise.
> 	* testsuite/23_containers/unordered_set/cons/deduction.cc: Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp1z/class-deduction88.C: New test.
> 	* g++.dg/cpp1z/class-deduction89.C: New test.
> 	* g++.dg/cpp1z/class-deduction90.C: New test.
> ---
>   gcc/cp/call.c                                 | 36 +++++++++++++++-
>   gcc/cp/cp-tree.h                              |  2 +
>   gcc/cp/pt.c                                   | 41 +++++++------------
>   .../g++.dg/cpp1z/class-deduction88.C          | 20 +++++++++
>   .../g++.dg/cpp1z/class-deduction89.C          | 15 +++++++
>   .../g++.dg/cpp1z/class-deduction90.C          | 16 ++++++++
>   .../23_containers/map/cons/deduction.cc       | 19 ---------
>   .../23_containers/multimap/cons/deduction.cc  | 20 ---------
>   .../23_containers/multiset/cons/deduction.cc  | 14 -------
>   .../23_containers/set/cons/deduction.cc       | 15 -------
>   .../unordered_map/cons/deduction.cc           | 16 --------
>   .../unordered_multimap/cons/deduction.cc      | 16 --------
>   .../unordered_multiset/cons/deduction.cc      | 10 -----
>   .../unordered_set/cons/deduction.cc           | 10 -----
>   14 files changed, 102 insertions(+), 148 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction88.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction89.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction90.C
> 
> diff --git a/gcc/cp/call.c b/gcc/cp/call.c
> index 9f03534c20c..aafc7acca24 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -4629,7 +4629,7 @@ perform_overload_resolution (tree fn,
>      functions.  */
>   
>   static void
> -print_error_for_call_failure (tree fn, vec<tree, va_gc> *args,
> +print_error_for_call_failure (tree fn, const vec<tree, va_gc> *args,
>   			      struct z_candidate *candidates)
>   {
>     tree targs = NULL_TREE;
> @@ -4654,6 +4654,40 @@ print_error_for_call_failure (tree fn, vec<tree, va_gc> *args,
>       print_z_candidates (loc, candidates);
>   }
>   
> +/* Perform overload resolution on the set of deduction guides DGUIDES
> +   using ARGS.  Returns the selected deduction guide, or error_mark_node
> +   if overload resolution fails.  */
> +
> +tree
> +perform_dguide_overload_resolution (tree dguides, const vec<tree, va_gc> *args,
> +				    tsubst_flags_t complain)
> +{
> +  z_candidate *candidates;
> +  bool any_viable_p;
> +  tree result;
> +
> +  gcc_assert (deduction_guide_p (OVL_FIRST (dguides)));
> +
> +  /* Get the high-water mark for the CONVERSION_OBSTACK.  */
> +  void *p = conversion_obstack_alloc (0);
> +
> +  z_candidate *cand = perform_overload_resolution (dguides, args, &candidates,
> +						   &any_viable_p, complain);
> +  if (!cand)
> +    {
> +      if (complain & tf_error)
> +	print_error_for_call_failure (dguides, args, candidates);
> +      result = error_mark_node;
> +    }
> +  else
> +    result = cand->fn;
> +
> +  /* Free all the conversions we allocated.  */
> +  obstack_free (&conversion_obstack, p);
> +
> +  return result;
> +}
> +
>   /* Return an expression for a call to FN (a namespace-scope function,
>      or a static member function) with the ARGS.  This may change
>      ARGS.  */
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 36f99ccf189..6f713719589 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -6437,6 +6437,8 @@ extern void complain_about_bad_argument	(location_t arg_loc,
>   						 tree from_type, tree to_type,
>   						 tree fndecl, int parmnum);
>   extern void maybe_inform_about_fndecl_for_bogus_argument_init (tree, int);
> +extern tree perform_dguide_overload_resolution	(tree, const vec<tree, va_gc> *,
> +						 tsubst_flags_t);
>   
>   
>   /* A class for recording information about access failures (e.g. private
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 15947b2c812..732fb405adf 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -29382,7 +29382,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
>       if (tree guide = maybe_aggr_guide (tmpl, init, args))
>         cands = lookup_add (guide, cands);
>   
> -  tree call = error_mark_node;
> +  tree fndecl = error_mark_node;
>   
>     /* If this is list-initialization and the class has a list constructor, first
>        try deducing from the list as a single argument, as [over.match.list].  */
> @@ -29396,11 +29396,9 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
>         }
>     if (list_cands)
>       {
> -      ++cp_unevaluated_operand;
> -      call = build_new_function_call (list_cands, &args, tf_decltype);
> -      --cp_unevaluated_operand;
> +      fndecl = perform_dguide_overload_resolution (list_cands, args, tf_none);
>   
> -      if (call == error_mark_node)
> +      if (fndecl == error_mark_node)
>   	{
>   	  /* That didn't work, now try treating the list as a sequence of
>   	     arguments.  */
> @@ -29416,31 +29414,22 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
>   	     "user-declared constructors", type);
>         return error_mark_node;
>       }
> -  else if (!cands && call == error_mark_node)
> +  else if (!cands && fndecl == error_mark_node)
>       {
>         error ("cannot deduce template arguments of %qT, as it has no viable "
>   	     "deduction guides", type);
>         return error_mark_node;
>       }
>   
> -  if (call == error_mark_node)
> -    {
> -      ++cp_unevaluated_operand;
> -      call = build_new_function_call (cands, &args, tf_decltype);
> -      --cp_unevaluated_operand;
> -    }
> +  if (fndecl == error_mark_node)
> +    fndecl = perform_dguide_overload_resolution (cands, args, tf_none);
>   
> -  if (call == error_mark_node)
> +  if (fndecl == error_mark_node)
>       {
>         if (complain & tf_warning_or_error)
>   	{
>   	  error ("class template argument deduction failed:");
> -
> -	  ++cp_unevaluated_operand;
> -	  call = build_new_function_call (cands, &args,
> -					  complain | tf_decltype);
> -	  --cp_unevaluated_operand;
> -
> +	  perform_dguide_overload_resolution (cands, args, complain);
>   	  if (elided)
>   	    inform (input_location, "explicit deduction guides not considered "
>   		    "for copy-initialization");
> @@ -29451,8 +29440,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
>        constructor is chosen, the initialization is ill-formed.  */
>     else if (flags & LOOKUP_ONLYCONVERTING)
>       {
> -      tree fndecl = cp_get_callee_fndecl_nofold (call);
> -      if (fndecl && DECL_NONCONVERTING_P (fndecl))
> +      if (DECL_NONCONVERTING_P (fndecl))
>   	{
>   	  if (complain & tf_warning_or_error)
>   	    {
> @@ -29470,12 +29458,10 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
>   
>     /* If CTAD succeeded but the type doesn't have any explicit deduction
>        guides, this deduction might not be what the user intended.  */
> -  if (call != error_mark_node && !any_dguides_p)
> +  if (fndecl != error_mark_node && !any_dguides_p)
>       {
> -      tree fndecl = cp_get_callee_fndecl_nofold (call);
> -      if (fndecl != NULL_TREE
> -	  && (!DECL_IN_SYSTEM_HEADER (fndecl)
> -	      || global_dc->dc_warn_system_headers)
> +      if ((!DECL_IN_SYSTEM_HEADER (fndecl)
> +	   || global_dc->dc_warn_system_headers)
>   	  && warning (OPT_Wctad_maybe_unsupported,
>   		      "%qT may not intend to support class template argument "
>   		      "deduction", type))
> @@ -29483,7 +29469,8 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
>   		"warning");
>       }
>   
> -  return cp_build_qualified_type (TREE_TYPE (call), cp_type_quals (ptype));
> +  return cp_build_qualified_type (TREE_TYPE (TREE_TYPE (fndecl)),
> +				  cp_type_quals (ptype));
>   }
>   
>   /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced
> diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction88.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction88.C
> new file mode 100644
> index 00000000000..f8fea966696
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction88.C
> @@ -0,0 +1,20 @@
> +// PR c++/86439
> +// { dg-do compile { target c++17 } }
> +
> +struct NC {
> +  NC() = default;
> +  NC(NC const&) = delete;
> +  NC& operator=(NC const&) = delete;
> +};
> +
> +template <int>
> +struct C {
> +  C(NC const&);
> +};
> +
> +C(NC) -> C<0>;
> +
> +int main() {
> +  NC nc;
> +  C c(nc);
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction89.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction89.C
> new file mode 100644
> index 00000000000..dd898573022
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction89.C
> @@ -0,0 +1,15 @@
> +// PR c++/86439
> +// { dg-do compile { target c++17 } }
> +
> +struct B { };
> +struct C { };
> +
> +template<class T>
> +struct A {
> +  A(T, B);
> +};
> +
> +template<class T>
> +A(T, C) -> A<T>;
> +
> +A a(0, {});
> diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction90.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction90.C
> new file mode 100644
> index 00000000000..8b93193c7b0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction90.C
> @@ -0,0 +1,16 @@
> +// PR c++/86439
> +// { dg-do compile { target c++17 } }
> +
> +struct less { };
> +struct allocator { };
> +
> +template<class T, class U = less, class V = allocator>
> +struct A {
> +  A(T, U);
> +  A(T, V);
> +};
> +
> +template<class T, class U = less>
> +A(T, U) -> A<T>;
> +
> +A a(0, {}); // { dg-error "ambiguous" }
> diff --git a/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc
> index e9628c4ac32..8def11ed574 100644
> --- a/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc
> +++ b/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc
> @@ -39,10 +39,6 @@ static_assert(std::is_same_v<
>   	      std::map<int, double>>);
>   */
>   
> -static_assert(std::is_same_v<
> -	      decltype(std::map{{std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}}, {}}),
> -	      std::map<int, double>>);
> -
>   /* This is not deducible, ambiguous candidates:
>    * map(initializer_list<value_type>, const Compare&, const _Allocator& = {})
>    * map(initializer_list<value_type>, const _Allocator&)
> @@ -90,11 +86,6 @@ void f()
>   				  std::less<int>{}, {}}),
>   		std::map<int, double>>);
>   
> -  static_assert(std::is_same_v<
> -		decltype(std::map(x.begin(), x.end(),
> -				  {})),
> -		std::map<int, double>>);
> -
>     static_assert(std::is_same_v<
>   		decltype(std::map{x.begin(), x.end(),
>   				  std::allocator<value_type>{}}),
> @@ -143,11 +134,6 @@ void g()
>   				  std::less<int>{}, {}}),
>   		std::map<int, double>>);
>   
> -  static_assert(std::is_same_v<
> -		decltype(std::map(x.begin(), x.end(),
> -				  {})),
> -		std::map<int, double>>);
> -
>     static_assert(std::is_same_v<
>   		decltype(std::map{x.begin(), x.end(),
>   				  std::allocator<value_type>{}}),
> @@ -193,11 +179,6 @@ void h()
>   				  std::less<int>{}, {}}),
>   		std::map<int, double>>);
>   
> -  static_assert(std::is_same_v<
> -		decltype(std::map(x.begin(), x.end(),
> -				  {})),
> -		std::map<int, double>>);
> -
>     static_assert(std::is_same_v<
>   		decltype(std::map{x.begin(), x.end(),
>   				  std::allocator<value_type>{}}),
> diff --git a/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc
> index 791cc963479..ff855081ab3 100644
> --- a/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc
> +++ b/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc
> @@ -40,11 +40,6 @@ static_assert(std::is_same_v<
>   	      std::multimap<int, double>>);
>   */
>   
> -static_assert(std::is_same_v<
> -	      decltype(std::multimap{{std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}},
> -		    {}}),
> -	      std::multimap<int, double>>);
> -
>   static_assert(std::is_same_v<
>   	      decltype(std::multimap{{value_type{1, 2.0}, {2, 3.0}, {3, 4.0}},
>   				     {}, SimpleAllocator<value_type>{}}),
> @@ -75,11 +70,6 @@ void f()
>   				       std::less<int>{}, {}}),
>   		std::multimap<int, double>>);
>   
> -  static_assert(std::is_same_v<
> -		decltype(std::multimap(x.begin(), x.end(),
> -				       {})),
> -		std::multimap<int, double>>);
> -
>     static_assert(std::is_same_v<
>   		decltype(std::multimap{x.begin(), x.end(),
>   		      {},
> @@ -117,11 +107,6 @@ void g()
>   				       std::less<int>{}, {}}),
>   		std::multimap<int, double>>);
>   
> -  static_assert(std::is_same_v<
> -		decltype(std::multimap(x.begin(), x.end(),
> -				       {})),
> -		std::multimap<int, double>>);
> -
>     static_assert(std::is_same_v<
>   		decltype(std::multimap{x.begin(), x.end(),
>   				       {},
> @@ -156,11 +141,6 @@ void h()
>   				       std::less<int>{}, {}}),
>   		std::multimap<int, double>>);
>   
> -  static_assert(std::is_same_v<
> -		decltype(std::multimap(x.begin(), x.end(),
> -				       {})),
> -		std::multimap<int, double>>);
> -
>     static_assert(std::is_same_v<
>   		decltype(std::multimap{x.begin(), x.end(),
>   				       {},
> diff --git a/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc
> index ad12755ccc6..be7ca237e78 100644
> --- a/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc
> +++ b/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc
> @@ -19,10 +19,6 @@ static_assert(std::is_same_v<
>   	      decltype(std::multiset{{1, 2, 3}, std::less<int>{}, {}}),
>   	      std::multiset<int>>);
>   
> -static_assert(std::is_same_v<
> -	      decltype(std::multiset{{1, 2, 3}, {}}),
> -	      std::multiset<int>>);
> -
>   static_assert(std::is_same_v<
>   	      decltype(std::multiset{{1, 2, 3}, SimpleAllocator<int>{}}),
>   	      std::multiset<int, std::less<int>, SimpleAllocator<int>>>);
> @@ -50,11 +46,6 @@ void f()
>   		      std::less<int>{}, {}}),
>   		std::multiset<int>>);
>   
> -  static_assert(std::is_same_v<
> -		decltype(std::multiset(x.begin(), x.end(),
> -				  {})),
> -		std::multiset<int>>);
> -
>     static_assert(std::is_same_v<
>   		decltype(std::multiset{x.begin(), x.end(),
>   				       std::allocator<int>{}}),
> @@ -101,11 +92,6 @@ void g()
>   				  std::less<int>{}, {}}),
>   		std::multiset<int>>);
>   
> -  static_assert(std::is_same_v<
> -		decltype(std::multiset(x.begin(), x.end(),
> -				  {})),
> -		std::multiset<int>>);
> -
>     static_assert(std::is_same_v<
>   		decltype(std::multiset{x.begin(), x.end(),
>   				  std::allocator<value_type>{}}),
> diff --git a/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc
> index 89a2c43b937..48d1a3ebbe2 100644
> --- a/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc
> +++ b/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc
> @@ -20,11 +20,6 @@ static_assert(std::is_same_v<
>   		    std::less<int>{}, {}}),
>   	      std::set<int>>);
>   
> -static_assert(std::is_same_v<
> -	      decltype(std::set{{1, 2, 3},
> -		    {}}),
> -	      std::set<int>>);
> -
>   static_assert(std::is_same_v<
>   	      decltype(std::set{{1, 2, 3},
>   		    SimpleAllocator<int>{}}),
> @@ -56,11 +51,6 @@ void f()
>   		      std::less<int>{}, {}}),
>   		std::set<int>>);
>   
> -  static_assert(std::is_same_v<
> -		decltype(std::set(x.begin(), x.end(),
> -				  {})),
> -		std::set<int>>);
> -
>     static_assert(std::is_same_v<
>   		decltype(std::set{x.begin(), x.end(),
>   		      {},
> @@ -102,11 +92,6 @@ void g()
>   				  std::less<int>{}, {}}),
>   		std::set<int>>);
>   
> -  static_assert(std::is_same_v<
> -		decltype(std::set(x.begin(), x.end(),
> -				  {})),
> -		std::set<int>>);
> -
>     static_assert(std::is_same_v<
>   		decltype(std::set{x.begin(), x.end(),
>   				  std::allocator<value_type>{}}),
> diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc
> index d8489b23f8a..bd266492b2a 100644
> --- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc
> +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc
> @@ -21,12 +21,6 @@ static_assert(std::is_same_v<
>   		1}),
>   	      std::unordered_map<int, double>>);
>   
> -static_assert(std::is_same_v<
> -	      decltype(std::unordered_map{{std::pair{1, 2.0},
> -		      {2, 3.0}, {3, 4.0}},
> -		    {}, std::hash<int>{}, {}}),
> -	      std::unordered_map<int, double>>);
> -
>   static_assert(std::is_same_v<
>   	      decltype(std::unordered_map{{std::pair{1, 2.0},
>   		      {2, 3.0}, {3, 4.0}},
> @@ -57,16 +51,6 @@ void f()
>   		      std::allocator<std::pair<const int, double>>{}}),
>   		std::unordered_map<int, double>>);
>   
> -  static_assert(std::is_same_v<
> -		decltype(std::unordered_map{x.begin(), x.end(),
> -		      {}, std::hash<int>{}, {}}),
> -		std::unordered_map<int, double>>);
> -
> -  static_assert(std::is_same_v<
> -		decltype(std::unordered_map(x.begin(), x.end(),
> -		      {})),
> -		std::unordered_map<int, double>>);
> -
>     static_assert(std::is_same_v<
>   		decltype(std::unordered_map{x.begin(), x.end(), 1}),
>   		std::unordered_map<int, double>>);
> diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc
> index 13f54d43451..74a0165574d 100644
> --- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc
> +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc
> @@ -15,12 +15,6 @@ static_assert(std::is_same_v<
>   		      {2, 3.0}, {3, 4.0}}}),
>   	      std::unordered_multimap<int, double>>);
>   
> -static_assert(std::is_same_v<
> -	      decltype(std::unordered_multimap{{std::pair{1, 2.0},
> -		      {2, 3.0}, {3, 4.0}},
> -		    {}, std::hash<int>{}, {}}),
> -	      std::unordered_multimap<int, double>>);
> -
>   static_assert(std::is_same_v<
>   	      decltype(std::unordered_multimap{{std::pair{1, 2.0},
>   		      {2, 3.0}, {3, 4.0}},
> @@ -66,16 +60,6 @@ void f()
>   		      std::allocator<std::pair<const int, double>>{}}),
>   		std::unordered_multimap<int, double>>);
>   
> -  static_assert(std::is_same_v<
> -		decltype(std::unordered_multimap{x.begin(), x.end(),
> -		      {}, std::hash<int>{}, {}}),
> -		std::unordered_multimap<int, double>>);
> -
> -  static_assert(std::is_same_v<
> -		decltype(std::unordered_multimap(x.begin(), x.end(),
> -				  {})),
> -		std::unordered_multimap<int, double>>);
> -
>     static_assert(std::is_same_v<
>   		decltype(std::unordered_multimap(x.begin(), x.end(), 1)),
>   		std::unordered_multimap<int, double>>);
> diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc
> index 1850237e44c..e3006fdbfe3 100644
> --- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc
> +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc
> @@ -9,11 +9,6 @@ static_assert(std::is_same_v<
>   	      decltype(std::unordered_multiset{1, 2, 3}),
>   	      std::unordered_multiset<int>>);
>   
> -static_assert(std::is_same_v<
> -	      decltype(std::unordered_multiset{{1, 2, 3},
> -		    0, std::hash<int>{}, {}}),
> -	      std::unordered_multiset<int>>);
> -
>   static_assert(std::is_same_v<
>   	      decltype(std::unordered_multiset{{1, 2, 3},
>   		    {}}),
> @@ -76,11 +71,6 @@ void f()
>   		      std::allocator<int>{}}),
>   		std::unordered_multiset<int>>);
>   
> -  static_assert(std::is_same_v<
> -		decltype(std::unordered_multiset{x.begin(), x.end(),
> -		      {}, std::hash<int>{}, {}}),
> -		std::unordered_multiset<int>>);
> -
>     static_assert(std::is_same_v<
>   		decltype(std::unordered_multiset(x.begin(), x.end(),
>   		      {})),
> diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc
> index a745dce0fba..69922cd92e7 100644
> --- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc
> +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc
> @@ -9,11 +9,6 @@ static_assert(std::is_same_v<
>   	      decltype(std::unordered_set{1, 2, 3}),
>   	      std::unordered_set<int>>);
>   
> -static_assert(std::is_same_v<
> -	      decltype(std::unordered_set{{1, 2, 3},
> -		    0, std::hash<int>{}, {}}),
> -	      std::unordered_set<int>>);
> -
>   static_assert(std::is_same_v<
>   	      decltype(std::unordered_set{{1, 2, 3},
>   		    {}}),
> @@ -71,11 +66,6 @@ void f()
>   		      std::allocator<int>{}}),
>   		std::unordered_set<int>>);
>   
> -  static_assert(std::is_same_v<
> -		decltype(std::unordered_set{x.begin(), x.end(),
> -		      {}, std::hash<int>{}, {}}),
> -		std::unordered_set<int>>);
> -
>     static_assert(std::is_same_v<
>   		decltype(std::unordered_set(x.begin(), x.end(),
>   		      {})),
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] c++: CTAD and deduction guide selection [PR86439]
  2021-06-22 18:45 [PATCH] c++: CTAD and deduction guide selection [PR86439] Patrick Palka
  2021-06-22 19:56 ` Jason Merrill
@ 2021-06-22 20:05 ` Jonathan Wakely
  2021-06-23  4:19   ` Patrick Palka
  1 sibling, 1 reply; 5+ messages in thread
From: Jonathan Wakely @ 2021-06-22 20:05 UTC (permalink / raw)
  To: Patrick Palka; +Cc: gcc Patches, libstdc++, jason

On Tue, 22 Jun 2021 at 19:45, Patrick Palka wrote:
> This change causes us to reject some container CTAD examples in the
> libstdc++ testsuite due to deduction failure for {}, which AFAICT is the
> correct behavior.  Previously, in the case of e.g. the first removed
> example for std::map, the type of {} would be deduced to less<int> as a
> side effect of forming the call to the selected guide
>
>   template<typename _Key, typename _Tp, typename _Compare = less<_Key>,
>              typename _Allocator = allocator<pair<const _Key, _Tp>>,
>              typename = _RequireNotAllocator<_Compare>,
>              typename = _RequireAllocator<_Allocator>>
>       map(initializer_list<pair<_Key, _Tp>>,
>           _Compare = _Compare(), _Allocator = _Allocator())
>       -> map<_Key, _Tp, _Compare, _Allocator>;
>
> which made later overload resolution for the constructor call
> unambiguous.  Now, the type of {} remains undeduced until constructor
> overload resolution, and we complain about ambiguity with the two
> constructors
>
>   map(initializer_list<value_type> __l,
>       const _Compare& __comp = _Compare(),
>       const allocator_type& __a = allocator_type())
>
>   map(initializer_list<value_type> __l, const allocator_type& __a)
>
> This patch just removes these problematic container CTAD examples.

Do all the problematic cases have a corresponding case that doesn't
use {} but uses an actual type?

If not, we might want to add such cases, to ensure we're still
covering all the cases that really *should* work.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] c++: CTAD and deduction guide selection [PR86439]
  2021-06-22 20:05 ` Jonathan Wakely
@ 2021-06-23  4:19   ` Patrick Palka
  2021-06-23  6:32     ` Jonathan Wakely
  0 siblings, 1 reply; 5+ messages in thread
From: Patrick Palka @ 2021-06-23  4:19 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Patrick Palka, gcc Patches, libstdc++, jason

On Tue, 22 Jun 2021, Jonathan Wakely wrote:

> On Tue, 22 Jun 2021 at 19:45, Patrick Palka wrote:
> > This change causes us to reject some container CTAD examples in the
> > libstdc++ testsuite due to deduction failure for {}, which AFAICT is the
> > correct behavior.  Previously, in the case of e.g. the first removed
> > example for std::map, the type of {} would be deduced to less<int> as a
> > side effect of forming the call to the selected guide
> >
> >   template<typename _Key, typename _Tp, typename _Compare = less<_Key>,
> >              typename _Allocator = allocator<pair<const _Key, _Tp>>,
> >              typename = _RequireNotAllocator<_Compare>,
> >              typename = _RequireAllocator<_Allocator>>
> >       map(initializer_list<pair<_Key, _Tp>>,
> >           _Compare = _Compare(), _Allocator = _Allocator())
> >       -> map<_Key, _Tp, _Compare, _Allocator>;
> >
> > which made later overload resolution for the constructor call
> > unambiguous.  Now, the type of {} remains undeduced until constructor
> > overload resolution, and we complain about ambiguity with the two
> > constructors
> >
> >   map(initializer_list<value_type> __l,
> >       const _Compare& __comp = _Compare(),
> >       const allocator_type& __a = allocator_type())
> >
> >   map(initializer_list<value_type> __l, const allocator_type& __a)
> >
> > This patch just removes these problematic container CTAD examples.
> 
> Do all the problematic cases have a corresponding case that doesn't
> use {} but uses an actual type?
> 
> If not, we might want to add such cases, to ensure we're still
> covering all the cases that really *should* work.

Ah, it looks like most tests have one such corresponding case, but since
the {} can potentially be an allocator or a function, for maximum
coverage we should have two corresponding cases.  So the revised patch
below instead replaces each problematic CTAD example with the other
untested case.

Interestingly two of these new CTAD examples for std::set and std::multiset
end up triggering an unrelated CTAD bug PR101174 on trunk, so the patch
comments out these adjusted examples for now.

-- >8 --

	PR c++/86439
	PR c++/101174

gcc/cp/ChangeLog:

	* call.c (print_error_for_call_failure): Constify 'args' parameter.
	(perform_dguide_overload_resolution): Define.
	* cp-tree.h: (perform_dguide_overload_resolution): Declare.
	* pt.c (do_class_deduction): Use perform_dguide_overload_resolution
	instead of build_new_function_call.  Don't use tf_decltype or
	set cp_unevaluated_operand.  Remove unnecessary NULL_TREE tests.

libstdc++-v3/ChangeLog:

	* testsuite/23_containers/map/cons/deduction.cc: Replace ambiguous
	CTAD examples.
	* testsuite/23_containers/multimap/cons/deduction.cc: Likewise.
	* testsuite/23_containers/multiset/cons/deduction.cc: Likewise.
	Mention one of the replaced examples is broken due to PR101174.
	* testsuite/23_containers/set/cons/deduction.cc: Likewise.
	* testsuite/23_containers/unordered_map/cons/deduction.cc: Replace
	ambiguous CTAD examples.
	* testsuite/23_containers/unordered_multimap/cons/deduction.cc:
	Likewise.
	* testsuite/23_containers/unordered_multiset/cons/deduction.cc:
	Likewise.
	* testsuite/23_containers/unordered_set/cons/deduction.cc: Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp1z/class-deduction88.C: New test.
	* g++.dg/cpp1z/class-deduction89.C: New test.
	* g++.dg/cpp1z/class-deduction90.C: New test.
---
 gcc/cp/call.c                                 | 36 +++++++++++++++-
 gcc/cp/cp-tree.h                              |  2 +
 gcc/cp/pt.c                                   | 41 +++++++------------
 .../g++.dg/cpp1z/class-deduction88.C          | 18 ++++++++
 .../g++.dg/cpp1z/class-deduction89.C          | 15 +++++++
 .../g++.dg/cpp1z/class-deduction90.C          | 16 ++++++++
 .../23_containers/map/cons/deduction.cc       |  8 ++--
 .../23_containers/multimap/cons/deduction.cc  |  8 ++--
 .../23_containers/multiset/cons/deduction.cc  |  8 ++--
 .../23_containers/set/cons/deduction.cc       |  8 ++--
 .../unordered_map/cons/deduction.cc           | 17 ++++++--
 .../unordered_multimap/cons/deduction.cc      | 17 ++++++--
 .../unordered_multiset/cons/deduction.cc      | 14 ++++++-
 .../unordered_set/cons/deduction.cc           | 14 ++++++-
 14 files changed, 170 insertions(+), 52 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction88.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction89.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction90.C

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 9f03534c20c..aafc7acca24 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4629,7 +4629,7 @@ perform_overload_resolution (tree fn,
    functions.  */
 
 static void
-print_error_for_call_failure (tree fn, vec<tree, va_gc> *args,
+print_error_for_call_failure (tree fn, const vec<tree, va_gc> *args,
 			      struct z_candidate *candidates)
 {
   tree targs = NULL_TREE;
@@ -4654,6 +4654,40 @@ print_error_for_call_failure (tree fn, vec<tree, va_gc> *args,
     print_z_candidates (loc, candidates);
 }
 
+/* Perform overload resolution on the set of deduction guides DGUIDES
+   using ARGS.  Returns the selected deduction guide, or error_mark_node
+   if overload resolution fails.  */
+
+tree
+perform_dguide_overload_resolution (tree dguides, const vec<tree, va_gc> *args,
+				    tsubst_flags_t complain)
+{
+  z_candidate *candidates;
+  bool any_viable_p;
+  tree result;
+
+  gcc_assert (deduction_guide_p (OVL_FIRST (dguides)));
+
+  /* Get the high-water mark for the CONVERSION_OBSTACK.  */
+  void *p = conversion_obstack_alloc (0);
+
+  z_candidate *cand = perform_overload_resolution (dguides, args, &candidates,
+						   &any_viable_p, complain);
+  if (!cand)
+    {
+      if (complain & tf_error)
+	print_error_for_call_failure (dguides, args, candidates);
+      result = error_mark_node;
+    }
+  else
+    result = cand->fn;
+
+  /* Free all the conversions we allocated.  */
+  obstack_free (&conversion_obstack, p);
+
+  return result;
+}
+
 /* Return an expression for a call to FN (a namespace-scope function,
    or a static member function) with the ARGS.  This may change
    ARGS.  */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 36f99ccf189..6f713719589 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6437,6 +6437,8 @@ extern void complain_about_bad_argument	(location_t arg_loc,
 						 tree from_type, tree to_type,
 						 tree fndecl, int parmnum);
 extern void maybe_inform_about_fndecl_for_bogus_argument_init (tree, int);
+extern tree perform_dguide_overload_resolution	(tree, const vec<tree, va_gc> *,
+						 tsubst_flags_t);
 
 
 /* A class for recording information about access failures (e.g. private
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 15947b2c812..732fb405adf 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -29382,7 +29382,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
     if (tree guide = maybe_aggr_guide (tmpl, init, args))
       cands = lookup_add (guide, cands);
 
-  tree call = error_mark_node;
+  tree fndecl = error_mark_node;
 
   /* If this is list-initialization and the class has a list constructor, first
      try deducing from the list as a single argument, as [over.match.list].  */
@@ -29396,11 +29396,9 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
       }
   if (list_cands)
     {
-      ++cp_unevaluated_operand;
-      call = build_new_function_call (list_cands, &args, tf_decltype);
-      --cp_unevaluated_operand;
+      fndecl = perform_dguide_overload_resolution (list_cands, args, tf_none);
 
-      if (call == error_mark_node)
+      if (fndecl == error_mark_node)
 	{
 	  /* That didn't work, now try treating the list as a sequence of
 	     arguments.  */
@@ -29416,31 +29414,22 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
 	     "user-declared constructors", type);
       return error_mark_node;
     }
-  else if (!cands && call == error_mark_node)
+  else if (!cands && fndecl == error_mark_node)
     {
       error ("cannot deduce template arguments of %qT, as it has no viable "
 	     "deduction guides", type);
       return error_mark_node;
     }
 
-  if (call == error_mark_node)
-    {
-      ++cp_unevaluated_operand;
-      call = build_new_function_call (cands, &args, tf_decltype);
-      --cp_unevaluated_operand;
-    }
+  if (fndecl == error_mark_node)
+    fndecl = perform_dguide_overload_resolution (cands, args, tf_none);
 
-  if (call == error_mark_node)
+  if (fndecl == error_mark_node)
     {
       if (complain & tf_warning_or_error)
 	{
 	  error ("class template argument deduction failed:");
-
-	  ++cp_unevaluated_operand;
-	  call = build_new_function_call (cands, &args,
-					  complain | tf_decltype);
-	  --cp_unevaluated_operand;
-
+	  perform_dguide_overload_resolution (cands, args, complain);
 	  if (elided)
 	    inform (input_location, "explicit deduction guides not considered "
 		    "for copy-initialization");
@@ -29451,8 +29440,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
      constructor is chosen, the initialization is ill-formed.  */
   else if (flags & LOOKUP_ONLYCONVERTING)
     {
-      tree fndecl = cp_get_callee_fndecl_nofold (call);
-      if (fndecl && DECL_NONCONVERTING_P (fndecl))
+      if (DECL_NONCONVERTING_P (fndecl))
 	{
 	  if (complain & tf_warning_or_error)
 	    {
@@ -29470,12 +29458,10 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
 
   /* If CTAD succeeded but the type doesn't have any explicit deduction
      guides, this deduction might not be what the user intended.  */
-  if (call != error_mark_node && !any_dguides_p)
+  if (fndecl != error_mark_node && !any_dguides_p)
     {
-      tree fndecl = cp_get_callee_fndecl_nofold (call);
-      if (fndecl != NULL_TREE
-	  && (!DECL_IN_SYSTEM_HEADER (fndecl)
-	      || global_dc->dc_warn_system_headers)
+      if ((!DECL_IN_SYSTEM_HEADER (fndecl)
+	   || global_dc->dc_warn_system_headers)
 	  && warning (OPT_Wctad_maybe_unsupported,
 		      "%qT may not intend to support class template argument "
 		      "deduction", type))
@@ -29483,7 +29469,8 @@ do_class_deduction (tree ptype, tree tmpl, tree init,
 		"warning");
     }
 
-  return cp_build_qualified_type (TREE_TYPE (call), cp_type_quals (ptype));
+  return cp_build_qualified_type (TREE_TYPE (TREE_TYPE (fndecl)),
+				  cp_type_quals (ptype));
 }
 
 /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction88.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction88.C
new file mode 100644
index 00000000000..be38fed2901
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction88.C
@@ -0,0 +1,18 @@
+// PR c++/86439
+// { dg-do compile { target c++17 } }
+
+struct NC {
+  NC() = default;
+  NC(NC const&) = delete;
+  NC& operator=(NC const&) = delete;
+};
+
+template <int>
+struct C {
+  C(NC const&);
+};
+
+C(NC) -> C<0>;
+
+NC nc;
+C c(nc);
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction89.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction89.C
new file mode 100644
index 00000000000..dd898573022
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction89.C
@@ -0,0 +1,15 @@
+// PR c++/86439
+// { dg-do compile { target c++17 } }
+
+struct B { };
+struct C { };
+
+template<class T>
+struct A {
+  A(T, B);
+};
+
+template<class T>
+A(T, C) -> A<T>;
+
+A a(0, {});
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction90.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction90.C
new file mode 100644
index 00000000000..8b93193c7b0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction90.C
@@ -0,0 +1,16 @@
+// PR c++/86439
+// { dg-do compile { target c++17 } }
+
+struct less { };
+struct allocator { };
+
+template<class T, class U = less, class V = allocator>
+struct A {
+  A(T, U);
+  A(T, V);
+};
+
+template<class T, class U = less>
+A(T, U) -> A<T>;
+
+A a(0, {}); // { dg-error "ambiguous" }
diff --git a/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc
index e9628c4ac32..e72033c38a6 100644
--- a/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/map/cons/deduction.cc
@@ -40,7 +40,7 @@ static_assert(std::is_same_v<
 */
 
 static_assert(std::is_same_v<
-	      decltype(std::map{{std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}}, {}}),
+	      decltype(std::map{{std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}}, std::less<int>{}}),
 	      std::map<int, double>>);
 
 /* This is not deducible, ambiguous candidates:
@@ -92,7 +92,7 @@ void f()
 
   static_assert(std::is_same_v<
 		decltype(std::map(x.begin(), x.end(),
-				  {})),
+				  std::less<int>{})),
 		std::map<int, double>>);
 
   static_assert(std::is_same_v<
@@ -145,7 +145,7 @@ void g()
 
   static_assert(std::is_same_v<
 		decltype(std::map(x.begin(), x.end(),
-				  {})),
+				  std::less<int>{})),
 		std::map<int, double>>);
 
   static_assert(std::is_same_v<
@@ -195,7 +195,7 @@ void h()
 
   static_assert(std::is_same_v<
 		decltype(std::map(x.begin(), x.end(),
-				  {})),
+				  std::less<int>{})),
 		std::map<int, double>>);
 
   static_assert(std::is_same_v<
diff --git a/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc
index 791cc963479..ffc7502d60c 100644
--- a/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/multimap/cons/deduction.cc
@@ -42,7 +42,7 @@ static_assert(std::is_same_v<
 
 static_assert(std::is_same_v<
 	      decltype(std::multimap{{std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}},
-		    {}}),
+		    std::less<int>{}}),
 	      std::multimap<int, double>>);
 
 static_assert(std::is_same_v<
@@ -77,7 +77,7 @@ void f()
 
   static_assert(std::is_same_v<
 		decltype(std::multimap(x.begin(), x.end(),
-				       {})),
+				       std::less<int>{})),
 		std::multimap<int, double>>);
 
   static_assert(std::is_same_v<
@@ -119,7 +119,7 @@ void g()
 
   static_assert(std::is_same_v<
 		decltype(std::multimap(x.begin(), x.end(),
-				       {})),
+				       std::less<int>{})),
 		std::multimap<int, double>>);
 
   static_assert(std::is_same_v<
@@ -158,7 +158,7 @@ void h()
 
   static_assert(std::is_same_v<
 		decltype(std::multimap(x.begin(), x.end(),
-				       {})),
+				       std::less<int>{})),
 		std::multimap<int, double>>);
 
   static_assert(std::is_same_v<
diff --git a/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc
index ad12755ccc6..a4ccc6fa467 100644
--- a/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/multiset/cons/deduction.cc
@@ -19,9 +19,11 @@ static_assert(std::is_same_v<
 	      decltype(std::multiset{{1, 2, 3}, std::less<int>{}, {}}),
 	      std::multiset<int>>);
 
+/* FIXME: GCC 12 rejects this due to PR c++/101174
 static_assert(std::is_same_v<
-	      decltype(std::multiset{{1, 2, 3}, {}}),
+	      decltype(std::multiset{{1, 2, 3}, std::less<int>{}}),
 	      std::multiset<int>>);
+*/
 
 static_assert(std::is_same_v<
 	      decltype(std::multiset{{1, 2, 3}, SimpleAllocator<int>{}}),
@@ -52,7 +54,7 @@ void f()
 
   static_assert(std::is_same_v<
 		decltype(std::multiset(x.begin(), x.end(),
-				  {})),
+				  std::less<int>{})),
 		std::multiset<int>>);
 
   static_assert(std::is_same_v<
@@ -103,7 +105,7 @@ void g()
 
   static_assert(std::is_same_v<
 		decltype(std::multiset(x.begin(), x.end(),
-				  {})),
+				  std::less<int>{})),
 		std::multiset<int>>);
 
   static_assert(std::is_same_v<
diff --git a/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc
index 89a2c43b937..0ae4c2a5c5f 100644
--- a/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/set/cons/deduction.cc
@@ -20,10 +20,12 @@ static_assert(std::is_same_v<
 		    std::less<int>{}, {}}),
 	      std::set<int>>);
 
+/* FIXME: GCC 12 rejects this due to PR c++/101174
 static_assert(std::is_same_v<
 	      decltype(std::set{{1, 2, 3},
-		    {}}),
+		    std::less<int>{}}),
 	      std::set<int>>);
+*/
 
 static_assert(std::is_same_v<
 	      decltype(std::set{{1, 2, 3},
@@ -58,7 +60,7 @@ void f()
 
   static_assert(std::is_same_v<
 		decltype(std::set(x.begin(), x.end(),
-				  {})),
+				  std::less<int>{})),
 		std::set<int>>);
 
   static_assert(std::is_same_v<
@@ -104,7 +106,7 @@ void g()
 
   static_assert(std::is_same_v<
 		decltype(std::set(x.begin(), x.end(),
-				  {})),
+				  std::less<int>{})),
 		std::set<int>>);
 
   static_assert(std::is_same_v<
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc
index d8489b23f8a..0785447a81b 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/deduction.cc
@@ -24,7 +24,13 @@ static_assert(std::is_same_v<
 static_assert(std::is_same_v<
 	      decltype(std::unordered_map{{std::pair{1, 2.0},
 		      {2, 3.0}, {3, 4.0}},
-		    {}, std::hash<int>{}, {}}),
+		    {}, std::hash<int>{}, std::equal_to<int>{}}),
+	      std::unordered_map<int, double>>);
+
+static_assert(std::is_same_v<
+	      decltype(std::unordered_map{{std::pair{1, 2.0},
+		      {2, 3.0}, {3, 4.0}},
+		    {}, std::hash<int>{}, std::allocator<std::pair<const int, double>>{}}),
 	      std::unordered_map<int, double>>);
 
 static_assert(std::is_same_v<
@@ -59,9 +65,14 @@ void f()
 
   static_assert(std::is_same_v<
 		decltype(std::unordered_map{x.begin(), x.end(),
-		      {}, std::hash<int>{}, {}}),
+		      {}, std::hash<int>{}, std::equal_to<int>{}}),
 		std::unordered_map<int, double>>);
-  
+
+  static_assert(std::is_same_v<
+		decltype(std::unordered_map{x.begin(), x.end(),
+		      {}, std::hash<int>{}, std::allocator<std::pair<const int, double>>{}}),
+		std::unordered_map<int, double>>);
+
   static_assert(std::is_same_v<
 		decltype(std::unordered_map(x.begin(), x.end(),
 		      {})),
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc
index 13f54d43451..d8a6f5136c9 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/deduction.cc
@@ -18,7 +18,13 @@ static_assert(std::is_same_v<
 static_assert(std::is_same_v<
 	      decltype(std::unordered_multimap{{std::pair{1, 2.0},
 		      {2, 3.0}, {3, 4.0}},
-		    {}, std::hash<int>{}, {}}),
+		    {}, std::hash<int>{}, std::equal_to<int>{}}),
+	      std::unordered_multimap<int, double>>);
+
+static_assert(std::is_same_v<
+	      decltype(std::unordered_multimap{{std::pair{1, 2.0},
+		      {2, 3.0}, {3, 4.0}},
+		    {}, std::hash<int>{}, std::allocator<std::pair<const int, double>>{}}),
 	      std::unordered_multimap<int, double>>);
 
 static_assert(std::is_same_v<
@@ -68,9 +74,14 @@ void f()
 
   static_assert(std::is_same_v<
 		decltype(std::unordered_multimap{x.begin(), x.end(),
-		      {}, std::hash<int>{}, {}}),
+		      {}, std::hash<int>{}, std::equal_to<int>{}}),
 		std::unordered_multimap<int, double>>);
-  
+
+  static_assert(std::is_same_v<
+		decltype(std::unordered_multimap{x.begin(), x.end(),
+		      {}, std::hash<int>{}, std::allocator<std::pair<const int, double>>{}}),
+		std::unordered_multimap<int, double>>);
+
   static_assert(std::is_same_v<
 		decltype(std::unordered_multimap(x.begin(), x.end(),
 				  {})),
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc
index 1850237e44c..25c2715ea26 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/deduction.cc
@@ -11,7 +11,12 @@ static_assert(std::is_same_v<
 
 static_assert(std::is_same_v<
 	      decltype(std::unordered_multiset{{1, 2, 3},
-		    0, std::hash<int>{}, {}}),
+		    0, std::hash<int>{}, std::equal_to<int>{}}),
+	      std::unordered_multiset<int>>);
+
+static_assert(std::is_same_v<
+	      decltype(std::unordered_multiset{{1, 2, 3},
+		    0, std::hash<int>{}, std::allocator<int>{}}),
 	      std::unordered_multiset<int>>);
 
 static_assert(std::is_same_v<
@@ -78,7 +83,12 @@ void f()
 
   static_assert(std::is_same_v<
 		decltype(std::unordered_multiset{x.begin(), x.end(),
-		      {}, std::hash<int>{}, {}}),
+		      {}, std::hash<int>{}, std::equal_to<int>{}}),
+		std::unordered_multiset<int>>);
+
+  static_assert(std::is_same_v<
+		decltype(std::unordered_multiset{x.begin(), x.end(),
+		      {}, std::hash<int>{}, std::allocator<int>{}}),
 		std::unordered_multiset<int>>);
 
   static_assert(std::is_same_v<
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc
index a745dce0fba..b8c45d2993d 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/deduction.cc
@@ -11,7 +11,12 @@ static_assert(std::is_same_v<
 
 static_assert(std::is_same_v<
 	      decltype(std::unordered_set{{1, 2, 3},
-		    0, std::hash<int>{}, {}}),
+		    0, std::hash<int>{}, std::equal_to<int>{}}),
+	      std::unordered_set<int>>);
+
+static_assert(std::is_same_v<
+	      decltype(std::unordered_set{{1, 2, 3},
+		    0, std::hash<int>{}, std::allocator<int>{}}),
 	      std::unordered_set<int>>);
 
 static_assert(std::is_same_v<
@@ -73,7 +78,12 @@ void f()
 
   static_assert(std::is_same_v<
 		decltype(std::unordered_set{x.begin(), x.end(),
-		      {}, std::hash<int>{}, {}}),
+		      {}, std::hash<int>{}, std::equal_to<int>{}}),
+		std::unordered_set<int>>);
+
+  static_assert(std::is_same_v<
+		decltype(std::unordered_set{x.begin(), x.end(),
+		      {}, std::hash<int>{}, std::allocator<int>{}}),
 		std::unordered_set<int>>);
 
   static_assert(std::is_same_v<
-- 
2.32.0.93.g670b81a890


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] c++: CTAD and deduction guide selection [PR86439]
  2021-06-23  4:19   ` Patrick Palka
@ 2021-06-23  6:32     ` Jonathan Wakely
  0 siblings, 0 replies; 5+ messages in thread
From: Jonathan Wakely @ 2021-06-23  6:32 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Jonathan Wakely, libstdc++, gcc Patches, jason

On Wed, 23 Jun 2021, 05:20 Patrick Palka via Libstdc++, <
libstdc++@gcc.gnu.org> wrote:

> On Tue, 22 Jun 2021, Jonathan Wakely wrote:
>
> > On Tue, 22 Jun 2021 at 19:45, Patrick Palka wrote:
> > > This change causes us to reject some container CTAD examples in the
> > > libstdc++ testsuite due to deduction failure for {}, which AFAICT is
> the
> > > correct behavior.  Previously, in the case of e.g. the first removed
> > > example for std::map, the type of {} would be deduced to less<int> as a
> > > side effect of forming the call to the selected guide
> > >
> > >   template<typename _Key, typename _Tp, typename _Compare = less<_Key>,
> > >              typename _Allocator = allocator<pair<const _Key, _Tp>>,
> > >              typename = _RequireNotAllocator<_Compare>,
> > >              typename = _RequireAllocator<_Allocator>>
> > >       map(initializer_list<pair<_Key, _Tp>>,
> > >           _Compare = _Compare(), _Allocator = _Allocator())
> > >       -> map<_Key, _Tp, _Compare, _Allocator>;
> > >
> > > which made later overload resolution for the constructor call
> > > unambiguous.  Now, the type of {} remains undeduced until constructor
> > > overload resolution, and we complain about ambiguity with the two
> > > constructors
> > >
> > >   map(initializer_list<value_type> __l,
> > >       const _Compare& __comp = _Compare(),
> > >       const allocator_type& __a = allocator_type())
> > >
> > >   map(initializer_list<value_type> __l, const allocator_type& __a)
> > >
> > > This patch just removes these problematic container CTAD examples.
> >
> > Do all the problematic cases have a corresponding case that doesn't
> > use {} but uses an actual type?
> >
> > If not, we might want to add such cases, to ensure we're still
> > covering all the cases that really *should* work.
>
> Ah, it looks like most tests have one such corresponding case, but since
> the {} can potentially be an allocator or a function, for maximum
> coverage we should have two corresponding cases.  So the revised patch
> below instead replaces each problematic CTAD example with the other
> untested case.
>
> Interestingly two of these new CTAD examples for std::set and std::multiset
> end up triggering an unrelated CTAD bug PR101174 on trunk, so the patch
> comments out these adjusted examples for now.
>

OK, thanks.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-06-23  6:32 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-22 18:45 [PATCH] c++: CTAD and deduction guide selection [PR86439] Patrick Palka
2021-06-22 19:56 ` Jason Merrill
2021-06-22 20:05 ` Jonathan Wakely
2021-06-23  4:19   ` Patrick Palka
2021-06-23  6:32     ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).